diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java index bec0848383fb..053f4448e1d2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java @@ -79,7 +79,7 @@ public class DefaultCodeFragmentFactory extends CodeFragmentFactory { return null; } - if (parameters.getInvocationCount() <= 1 && JavaCompletionUtil.containsMethodCalls(expression)) { + if (parameters.getInvocationCount() <= 1 && JavaCompletionUtil.mayHaveSideEffects(expression)) { final CompletionService service = CompletionService.getCompletionService(); if (service.getAdvertisementText() == null && parameters.getInvocationCount() < 2) { service.setAdvertisementText("Invoke completion once more to see runtime type variants"); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index a97e1316b6ed..2e168b6291ab 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -677,18 +677,19 @@ public class JavaCompletionUtil { return ret; } - @Nullable - static PsiElement getQualifier(final PsiElement element) { - return element instanceof PsiJavaCodeReferenceElement ? ((PsiJavaCodeReferenceElement)element).getQualifier() : null; - } - - public static boolean containsMethodCalls(@Nullable final PsiElement qualifier) { - if (qualifier == null) return false; - if (qualifier instanceof PsiMethodCallExpression || qualifier instanceof PsiNewExpression) return true; - if (qualifier instanceof PsiArrayAccessExpression) { - return containsMethodCalls(((PsiArrayAccessExpression)qualifier).getArrayExpression()); + public static boolean mayHaveSideEffects(@Nullable final PsiElement element) { + if (element == null) return false; + if (element instanceof PsiMethodCallExpression || element instanceof PsiNewExpression) return true; + if (element instanceof PsiTypeCastExpression) { + return mayHaveSideEffects(((PsiTypeCastExpression)element).getOperand()); } - return containsMethodCalls(getQualifier(qualifier)); + if (element instanceof PsiArrayAccessExpression) { + return mayHaveSideEffects(((PsiArrayAccessExpression)element).getArrayExpression()); + } + if (element instanceof PsiJavaCodeReferenceElement) { + return mayHaveSideEffects(((PsiJavaCodeReferenceElement)element).getQualifier()); + } + return true; } public static void insertClassReference(@NotNull PsiClass psiClass, @NotNull PsiFile file, int offset) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index 454fcf02d7b1..b164555b8576 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -274,7 +274,9 @@ public class ReferenceExpressionCompletionContributor { } if (itemType == null) return; - final PsiElement qualifier = JavaCompletionUtil.getQualifier(reference.getElement()); + final PsiElement element1 = reference.getElement(); + final PsiElement qualifier = + element1 instanceof PsiJavaCodeReferenceElement ? ((PsiJavaCodeReferenceElement)element1).getQualifier() : null; final PsiType expectedType = parameters.getExpectedType(); if (!OBJECT_METHOD_PATTERN.accepts(object) || allowGetClass(object, parameters)) { if (parameters.getParameters().getInvocationCount() >= 3 || !itemType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { @@ -398,7 +400,7 @@ public class ReferenceExpressionCompletionContributor { } final String bracketSpace = getSpace(CodeStyleSettingsManager.getSettings(element.getProject()).SPACE_WITHIN_BRACKETS); - if (object instanceof PsiVariable && !JavaCompletionUtil.containsMethodCalls(qualifier)) { + if (object instanceof PsiVariable && !JavaCompletionUtil.mayHaveSideEffects(qualifier)) { final PsiVariable variable = (PsiVariable)object; addToArrayConversion(element, prefix, "new " + componentType.getCanonicalText() + diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index f51ac1972979..51e886a9d872 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -1075,38 +1075,33 @@ class ControlFlowAnalyzer extends JavaElementVisitor { startElement(expression); DfaValue dfaValue = myFactory.create(expression); - if (dfaValue != null) { - addInstruction(new PushInstruction(dfaValue, expression)); - } - else { - PsiExpression condition = expression.getCondition(); + PsiExpression condition = expression.getCondition(); - PsiExpression thenExpression = expression.getThenExpression(); - PsiExpression elseExpression = expression.getElseExpression(); + PsiExpression thenExpression = expression.getThenExpression(); + PsiExpression elseExpression = expression.getElseExpression(); - final int elseOffset = elseExpression == null ? getEndOffset(expression) - 1 : getStartOffset(elseExpression); - if (thenExpression != null) { - condition.accept(this); - generateBoxingUnboxingInstructionFor(condition, PsiType.BOOLEAN); - PsiType type = expression.getType(); - addInstruction(new ConditionalGotoInstruction(elseOffset, true, condition)); - thenExpression.accept(this); - generateBoxingUnboxingInstructionFor(thenExpression,type); + final int elseOffset = elseExpression == null ? getEndOffset(expression) - 1 : getStartOffset(elseExpression); + if (thenExpression != null) { + condition.accept(this); + generateBoxingUnboxingInstructionFor(condition, PsiType.BOOLEAN); + PsiType type = expression.getType(); + addInstruction(new ConditionalGotoInstruction(elseOffset, true, condition)); + thenExpression.accept(this); + generateBoxingUnboxingInstructionFor(thenExpression,type); - addInstruction(new GotoInstruction(getEndOffset(expression))); + addInstruction(new GotoInstruction(getEndOffset(expression))); - if (elseExpression != null) { - elseExpression.accept(this); - generateBoxingUnboxingInstructionFor(elseExpression,type); - } - else { - pushUnknown(); - } + if (elseExpression != null) { + elseExpression.accept(this); + generateBoxingUnboxingInstructionFor(elseExpression,type); } else { pushUnknown(); } } + else { + pushUnknown(); + } finishElement(expression); } 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 8da301fb80c6..c1ab84ce0bb0 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 @@ -125,13 +125,13 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { if (node == null) { return true; } + final IElementType type = node.getElementType(); - if (type == JavaDocTokenType.DOC_TAG_VALUE_TOKEN) { + if (type == JavaDocElementType.DOC_TAG_VALUE_ELEMENT) { return PsiTreeUtil.getParentOfType(parent, PsiDocMethodOrFieldRef.class) != null; } - return type == JavaDocElementType.DOC_COMMENT || type == JavaDocElementType.DOC_TAG - || type == JavaDocElementType.DOC_INLINE_TAG; + return type == JavaDocElementType.DOC_COMMENT || type == JavaDocElementType.DOC_TAG || type == JavaDocElementType.DOC_INLINE_TAG; } private void init(final ASTNode child) { @@ -1096,9 +1096,8 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { else if (myRole1 == ChildRole.OPERATION_SIGN) { createSpaceInCode(mySettings.SPACE_AROUND_UNARY_OPERATOR); } - else if (myChild1.getElementType() == JavaDocTokenType.DOC_TAG_VALUE_TOKEN - && myChild2.getElementType() == JavaDocTokenType.DOC_TAG_VALUE_TOKEN) - { + else if ((myType1 == JavaDocTokenType.DOC_TAG_VALUE_TOKEN || myType1 == JavaDocElementType.DOC_TAG_VALUE_ELEMENT) && + (myType2 == JavaDocTokenType.DOC_TAG_VALUE_TOKEN || myType2 == JavaDocElementType.DOC_TAG_VALUE_ELEMENT)) { createSpaceInCode(true); } else if (myRole1 == ChildRole.COMMA) { @@ -1516,7 +1515,7 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { } @Override public void visitDocTag(PsiDocTag tag) { - if (myChild1.getElementType() == JavaDocTokenType.DOC_TAG_NAME && myChild2.getElementType() == JavaDocTokenType.DOC_TAG_VALUE_TOKEN) { + if (myType1 == JavaDocTokenType.DOC_TAG_NAME && myType2 == JavaDocElementType.DOC_TAG_VALUE_ELEMENT) { myResult = Spacing.createSpacing(1, 1, 0, false, 0); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java index 9549f72b7ed1..20f7ab1e2f44 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,9 @@ import com.intellij.psi.tree.IElementType; * @author max */ public class JavaASTFactory extends CoreJavaASTFactory { - @Override public CompositeElement createComposite(final IElementType type) { - if (type == DOC_TAG_VALUE_TOKEN) { + if (type == DOC_TAG_VALUE_ELEMENT) { return new PsiDocTagValueImpl(); } diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/JavadocParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/JavadocParser.java index b72e4a88d0d5..78abd7fd19e5 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/JavadocParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/JavadocParser.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. @@ -147,7 +147,7 @@ public class JavadocParser { final PsiBuilder.Marker tagValue = builder.mark(); builder.remapCurrentToken(JavaDocElementType.DOC_REFERENCE_HOLDER); builder.advanceLexer(); - tagValue.done(JavaDocTokenType.DOC_TAG_VALUE_TOKEN); + tagValue.done(JavaDocElementType.DOC_TAG_VALUE_ELEMENT); } else if (!isInline && tagName != null && tagName.equals(PARAM_TAG)) { parseSimpleTagValue(builder, true); @@ -187,7 +187,7 @@ public class JavadocParser { else { final PsiBuilder.Marker tagValue = builder.mark(); builder.advanceLexer(); - tagValue.done(JavaDocTokenType.DOC_TAG_VALUE_TOKEN); + tagValue.done(JavaDocElementType.DOC_TAG_VALUE_ELEMENT); } } @@ -217,7 +217,7 @@ public class JavadocParser { } } else if (tokenType == JavaDocTokenType.DOC_TAG_VALUE_RPAREN) { - subValue.done(JavaDocTokenType.DOC_TAG_VALUE_TOKEN); + subValue.done(JavaDocElementType.DOC_TAG_VALUE_ELEMENT); builder.advanceLexer(); refStart.done(JavaDocElementType.DOC_METHOD_OR_FIELD_REF); return; @@ -227,7 +227,7 @@ public class JavadocParser { } } - subValue.done(JavaDocTokenType.DOC_TAG_VALUE_TOKEN); + subValue.done(JavaDocElementType.DOC_TAG_VALUE_ELEMENT); } refStart.done(JavaDocElementType.DOC_METHOD_OR_FIELD_REF); @@ -238,7 +238,7 @@ public class JavadocParser { while (TAG_VALUES_SET.contains(getTokenType(builder))) { builder.advanceLexer(); } - tagValue.done(parameter ? JavaDocElementType.DOC_PARAMETER_REF : JavaDocTokenType.DOC_TAG_VALUE_TOKEN); + tagValue.done(parameter ? JavaDocElementType.DOC_PARAMETER_REF : JavaDocElementType.DOC_TAG_VALUE_ELEMENT); } @Nullable diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index c4e790fa9485..f69fdf7127ea 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,7 +99,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme i == JavaElementType.THIS_EXPRESSION || i == JavaElementType.SUPER_EXPRESSION || i == JavaDocElementType.DOC_METHOD_OR_FIELD_REF || - i == JavaDocTokenType.DOC_TAG_VALUE_TOKEN || + i == JavaDocElementType.DOC_TAG_VALUE_ELEMENT || i == JavaElementType.REFERENCE_PARAMETER_LIST || i == JavaElementType.ANNOTATION) { if (isQualified()) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/CorePsiDocTagValueImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/CorePsiDocTagValueImpl.java index bf790cb612cc..d79afae2c1cc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/CorePsiDocTagValueImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/CorePsiDocTagValueImpl.java @@ -21,6 +21,7 @@ import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.CompositePsiElement; +import com.intellij.psi.impl.source.tree.JavaDocElementType; import com.intellij.psi.javadoc.PsiDocTagValue; import org.jetbrains.annotations.NotNull; @@ -29,7 +30,7 @@ import org.jetbrains.annotations.NotNull; */ public class CorePsiDocTagValueImpl extends CompositePsiElement implements PsiDocTagValue { public CorePsiDocTagValueImpl() { - super(JavaDocTokenType.DOC_TAG_VALUE_TOKEN); + super(JavaDocElementType.DOC_TAG_VALUE_ELEMENT); } @Override @@ -47,6 +48,7 @@ public class CorePsiDocTagValueImpl extends CompositePsiElement implements PsiDo if (child.getElementType() == JavaDocTokenType.DOC_TAG_VALUE_COMMA) { return ChildRole.COMMA; } + return super.getChildRole(child); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java index 4fb485baf727..36f7c61047f5 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,7 @@ package com.intellij.psi.impl.source.javadoc; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; -import com.intellij.psi.impl.source.Constants; -import com.intellij.psi.impl.source.tree.CompositePsiElement; -import com.intellij.psi.impl.source.tree.Factory; -import com.intellij.psi.impl.source.tree.LeafElement; -import com.intellij.psi.impl.source.tree.SharedImplUtil; +import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; @@ -43,9 +39,8 @@ import java.util.Set; * @author mike */ public class PsiDocParamRef extends CompositePsiElement implements PsiDocTagValue { - public PsiDocParamRef() { - super(Constants.DOC_PARAMETER_REF); + super(JavaDocElementType.DOC_PARAMETER_REF); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocTagImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocTagImpl.java index ae89a54207ee..9f2b59ec5538 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocTagImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocTagImpl.java @@ -16,13 +16,9 @@ package com.intellij.psi.impl.source.javadoc; import com.intellij.lang.ASTNode; -import com.intellij.psi.JavaElementVisitor; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiReference; +import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.Constants; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.CompositePsiElement; @@ -37,9 +33,10 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; public class PsiDocTagImpl extends CompositePsiElement implements PsiDocTag, Constants { - private static final TokenSet VALUE_BIT_SET = TokenSet.create( - JAVA_CODE_REFERENCE, DOC_TAG_VALUE_TOKEN, DOC_METHOD_OR_FIELD_REF, DOC_PARAMETER_REF, - DOC_COMMENT_DATA, DOC_INLINE_TAG, DOC_REFERENCE_HOLDER); + private static final TokenSet TAG_VALUE_BIT_SET = TokenSet.create( + DOC_TAG_VALUE_ELEMENT, DOC_METHOD_OR_FIELD_REF, DOC_PARAMETER_REF); + private static final TokenSet VALUE_BIT_SET = TokenSet.orSet(TAG_VALUE_BIT_SET, TokenSet.create( + DOC_TAG_VALUE_TOKEN, JAVA_CODE_REFERENCE, DOC_COMMENT_DATA, DOC_INLINE_TAG, DOC_REFERENCE_HOLDER)); public PsiDocTagImpl() { super(DOC_TAG); @@ -47,17 +44,17 @@ public class PsiDocTagImpl extends CompositePsiElement implements PsiDocTag, Con @Override public PsiDocComment getContainingComment() { - return (PsiDocComment)SourceTreeToPsiMap.treeElementToPsi(getTreeParent()); + return (PsiDocComment)getParent(); } @Override public PsiElement getNameElement() { - return findChildByRoleAsPsiElement(ChildRole.DOC_TAG_NAME); + return findPsiChildByType(DOC_TAG_NAME); } @Override public PsiDocTagValue getValueElement() { - return (PsiDocTagValue)findChildByRoleAsPsiElement(ChildRole.DOC_TAG_VALUE); + return (PsiDocTagValue)findPsiChildByType(TAG_VALUE_BIT_SET); } @Override @@ -65,6 +62,7 @@ public class PsiDocTagImpl extends CompositePsiElement implements PsiDocTag, Con return getChildrenAsPsiElements(VALUE_BIT_SET, PsiElement.ARRAY_FACTORY); } + @NotNull @Override public String getName() { if (getNameElement() == null) return ""; @@ -79,7 +77,7 @@ public class PsiDocTagImpl extends CompositePsiElement implements PsiDocTag, Con @Override public int getChildRole(ASTNode child) { - assert (child.getTreeParent() == this); + assert child.getTreeParent() == this : child.getTreeParent(); IElementType i = child.getElementType(); if (i == DOC_TAG_NAME) { return ChildRole.DOC_TAG_NAME; @@ -90,10 +88,7 @@ public class PsiDocTagImpl extends CompositePsiElement implements PsiDocTag, Con else if (i == DOC_COMMENT_LEADING_ASTERISKS) { return ChildRole.DOC_COMMENT_ASTERISKS; } - else if (i == DOC_TAG_VALUE_TOKEN) { - return ChildRole.DOC_TAG_VALUE; - } - else if (i == DOC_METHOD_OR_FIELD_REF || i == DOC_PARAMETER_REF) { + else if (TAG_VALUE_BIT_SET.contains(i)) { return ChildRole.DOC_TAG_VALUE; } else { @@ -104,7 +99,7 @@ public class PsiDocTagImpl extends CompositePsiElement implements PsiDocTag, Con @Override @NotNull public PsiReference[] getReferences() { - return ReferenceProvidersRegistry.getReferencesFromProviders(this, PsiDocTag.class); + return ReferenceProvidersRegistry.getReferencesFromProviders(this, PsiReferenceService.Hints.NO_HINTS); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiInlineDocTagImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiInlineDocTagImpl.java similarity index 81% rename from java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiInlineDocTagImpl.java rename to java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiInlineDocTagImpl.java index 5e6e534a1f78..38466a5f6cb1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiInlineDocTagImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiInlineDocTagImpl.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi.impl.source.tree.java; +package com.intellij.psi.impl.source.javadoc; import com.intellij.lang.ASTNode; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; @@ -36,11 +35,10 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; public class PsiInlineDocTagImpl extends CompositePsiElement implements PsiInlineDocTag, Constants { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiInlineDocTagImpl"); - - private static final TokenSet VALUE_BIT_SET = TokenSet.create( - JAVA_CODE_REFERENCE, DOC_TAG_VALUE_TOKEN, DOC_METHOD_OR_FIELD_REF, DOC_COMMENT_DATA, DOC_INLINE_TAG, - DOC_REFERENCE_HOLDER, WHITE_SPACE, DOC_COMMENT_BAD_CHARACTER); + private static final TokenSet TAG_VALUE_BIT_SET = TokenSet.create( + DOC_TAG_VALUE_ELEMENT, DOC_METHOD_OR_FIELD_REF); + private static final TokenSet VALUE_BIT_SET = TokenSet.orSet(TAG_VALUE_BIT_SET, TokenSet.create( + JAVA_CODE_REFERENCE, DOC_TAG_VALUE_TOKEN, DOC_COMMENT_DATA, DOC_INLINE_TAG, DOC_REFERENCE_HOLDER, WHITE_SPACE, DOC_COMMENT_BAD_CHARACTER)); public PsiInlineDocTagImpl() { super(DOC_INLINE_TAG); @@ -57,7 +55,7 @@ public class PsiInlineDocTagImpl extends CompositePsiElement implements PsiInlin @Override public PsiElement getNameElement() { - return findChildByRoleAsPsiElement(ChildRole.DOC_TAG_NAME); + return findPsiChildByType(DOC_TAG_NAME); } @Override @@ -67,7 +65,7 @@ public class PsiInlineDocTagImpl extends CompositePsiElement implements PsiInlin @Override public PsiDocTagValue getValueElement() { - return (PsiDocTagValue)findChildByRoleAsPsiElement(ChildRole.DOC_TAG_VALUE); + return (PsiDocTagValue)findPsiChildByType(TAG_VALUE_BIT_SET); } @Override @@ -79,7 +77,7 @@ public class PsiInlineDocTagImpl extends CompositePsiElement implements PsiInlin @Override public int getChildRole(ASTNode child) { - LOG.assertTrue(child.getTreeParent() == this); + assert child.getTreeParent() == this : child.getTreeParent(); IElementType i = child.getElementType(); if (i == DOC_TAG_NAME) { return ChildRole.DOC_TAG_NAME; @@ -93,10 +91,7 @@ public class PsiInlineDocTagImpl extends CompositePsiElement implements PsiInlin else if (i == DOC_INLINE_TAG_END) { return ChildRole.DOC_INLINE_TAG_END; } - else if (i == DOC_TAG_VALUE_TOKEN) { - return ChildRole.DOC_TAG_VALUE; - } - else if (i == DOC_METHOD_OR_FIELD_REF) { + else if (TAG_VALUE_BIT_SET.contains(i)) { return ChildRole.DOC_TAG_VALUE; } else { @@ -124,4 +119,4 @@ public class PsiInlineDocTagImpl extends CompositePsiElement implements PsiInlin PsiImplUtil.setName(getNameElement(), name); return this; } -} \ No newline at end of file +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/CoreJavaASTFactory.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/CoreJavaASTFactory.java index c9b6e5552676..dc7b6e576871 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/CoreJavaASTFactory.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/CoreJavaASTFactory.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. @@ -49,6 +49,7 @@ public class CoreJavaASTFactory extends ASTFactory implements Constants { return new PsiJavaTokenImpl(type, text); } else if (type instanceof IJavaDocElementType) { + assert type != DOC_TAG_VALUE_ELEMENT; return new PsiDocTokenImpl(type, text); } @@ -57,7 +58,7 @@ public class CoreJavaASTFactory extends ASTFactory implements Constants { @Override public CompositeElement createComposite(IElementType type) { - if (type == DOC_TAG_VALUE_TOKEN) { + if (type == DOC_TAG_VALUE_ELEMENT) { return new CorePsiDocTagValueImpl(); } return null; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java index 4c4776cb1653..71df6027483e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.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. @@ -29,7 +29,7 @@ import com.intellij.psi.impl.source.javadoc.PsiDocCommentImpl; import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef; import com.intellij.psi.impl.source.javadoc.PsiDocParamRef; import com.intellij.psi.impl.source.javadoc.PsiDocTagImpl; -import com.intellij.psi.impl.source.tree.java.PsiInlineDocTagImpl; +import com.intellij.psi.impl.source.javadoc.PsiInlineDocTagImpl; import com.intellij.psi.tree.*; import com.intellij.psi.tree.java.IJavaDocElementType; import com.intellij.util.ReflectionUtil; @@ -70,6 +70,7 @@ public interface JavaDocElementType { IElementType DOC_INLINE_TAG = new JavaDocCompositeElementType("DOC_INLINE_TAG", PsiInlineDocTagImpl.class); IElementType DOC_METHOD_OR_FIELD_REF = new JavaDocCompositeElementType("DOC_METHOD_OR_FIELD_REF", PsiDocMethodOrFieldRef.class); IElementType DOC_PARAMETER_REF = new JavaDocCompositeElementType("DOC_PARAMETER_REF", PsiDocParamRef.class); + IElementType DOC_TAG_VALUE_ELEMENT = new IJavaDocElementType("DOC_TAG_VALUE_ELEMENT"); ILazyParseableElementType DOC_REFERENCE_HOLDER = new JavaDocLazyElementType("DOC_REFERENCE_HOLDER") { private final JavaParserUtil.ParserWrapper myParser = new JavaParserUtil.ParserWrapper() { @@ -135,6 +136,6 @@ public interface JavaDocElementType { }; TokenSet ALL_JAVADOC_ELEMENTS = TokenSet.create( - DOC_TAG, DOC_INLINE_TAG, DOC_METHOD_OR_FIELD_REF, DOC_PARAMETER_REF, DOC_REFERENCE_HOLDER, DOC_TYPE_HOLDER, DOC_COMMENT - ); + DOC_TAG, DOC_INLINE_TAG, DOC_METHOD_OR_FIELD_REF, DOC_PARAMETER_REF, DOC_TAG_VALUE_ELEMENT, + DOC_REFERENCE_HOLDER, DOC_TYPE_HOLDER, DOC_COMMENT); } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/StringTernaryAlwaysTrue.java b/java/java-tests/testData/inspection/dataFlow/fixture/StringTernaryAlwaysTrue.java new file mode 100644 index 000000000000..93255d9a79b8 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/StringTernaryAlwaysTrue.java @@ -0,0 +1,12 @@ +class Foo { + public void foo() { + final boolean flag = true; + + bar(flag ? "a" : "b", + flag ? new String[]{"aa"} : new String[]{"bb"} + ); + } + + void bar(String b, String[] a) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/Exception0.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/Exception0.txt index 9254cba2a145..b3935666fc28 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/Exception0.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/Exception0.txt @@ -25,7 +25,7 @@ PsiJavaFile:Exception0.java PsiDocTag:@throws PsiDocToken:DOC_TAG_NAME('@throws') PsiWhiteSpace(' ') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_REFERENCE_HOLDER) PsiJavaCodeReferenceElement:java.lang.Exception PsiJavaCodeReferenceElement:java.lang diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag1.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag1.txt index 983c2c305f61..1975d6a75cf5 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag1.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag1.txt @@ -15,7 +15,7 @@ PsiJavaFile:InlineTag1.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('somefunc') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:String PsiJavaCodeReferenceElement:String diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag2.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag2.txt index 9bba0d6bc228..9165b8960367 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag2.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag2.txt @@ -15,7 +15,7 @@ PsiJavaFile:InlineTag2.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('somefunc') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:String PsiJavaCodeReferenceElement:String diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag3.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag3.txt index e74ee40b22bd..fb591f4269c2 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag3.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/InlineTag3.txt @@ -15,7 +15,7 @@ PsiJavaFile:InlineTag3.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('somefunc') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:String PsiJavaCodeReferenceElement:String diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag1.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag1.txt index b1bae863f3b4..d7f6a22bf259 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag1.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag1.txt @@ -30,7 +30,7 @@ PsiJavaFile:LinkPlainTag1.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('equals') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:java.lang.Object PsiJavaCodeReferenceElement:java.lang.Object diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag2.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag2.txt index ba779cc5e45a..79e2ec31d002 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag2.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkPlainTag2.txt @@ -10,7 +10,7 @@ PsiJavaFile:LinkPlainTag2.java PsiDocTag:@linkplain PsiDocToken:DOC_TAG_NAME('@linkplain') PsiWhiteSpace(' ') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_TOKEN('java.lang.String') PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('equals') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag1.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag1.txt index 588adbae3d2e..f5fde4f3d333 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag1.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag1.txt @@ -30,7 +30,7 @@ PsiJavaFile:LinkTag1.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('equals') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:java.lang.Object PsiJavaCodeReferenceElement:java.lang.Object diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag2.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag2.txt index 5bb0d66a89f3..af4cf7d2b185 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag2.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag2.txt @@ -10,7 +10,7 @@ PsiJavaFile:LinkTag2.java PsiDocTag:@link PsiDocToken:DOC_TAG_NAME('@link') PsiWhiteSpace(' ') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_TOKEN('java.lang.String') PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('equals') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag3.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag3.txt index 8a8940b8e0b3..b1ea51c9d1af 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag3.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag3.txt @@ -17,7 +17,7 @@ PsiJavaFile:LinkTag3.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('foo') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_RPAREN(')') PsiDocToken:DOC_INLINE_TAG_END('}') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag4.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag4.txt index 93a0946316fc..a08d012cd2f2 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag4.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag4.txt @@ -16,7 +16,7 @@ PsiJavaFile:LinkTag4.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('foo') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_RPAREN(')') PsiDocToken:DOC_INLINE_TAG_END('}') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag5.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag5.txt index 6fe4b9bb0d46..6aeebb155f30 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag5.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag5.txt @@ -15,7 +15,7 @@ PsiJavaFile:LinkTag5.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('foo') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_RPAREN(')') PsiDocToken:DOC_INLINE_TAG_END('}') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag6.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag6.txt index 24d4ab93bb89..1cc176462b4e 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag6.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/LinkTag6.txt @@ -15,7 +15,7 @@ PsiJavaFile:LinkTag6.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('foo') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_RPAREN(')') PsiDocToken:DOC_INLINE_TAG_END('}') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag10.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag10.txt index 94bc09223507..95b2f7f607a3 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag10.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag10.txt @@ -29,7 +29,7 @@ PsiJavaFile:SeeTag10.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('equals') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:java.lang.Object PsiJavaCodeReferenceElement:java.lang.Object diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag11.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag11.txt index fec603ea5b39..f58d76b72fd8 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag11.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag11.txt @@ -29,7 +29,7 @@ PsiJavaFile:SeeTag11.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('wait') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_RPAREN(')') PsiWhiteSpace('\n ') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag12.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag12.txt index 6ef08071804c..ac4dd62c07d2 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag12.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag12.txt @@ -14,7 +14,7 @@ PsiJavaFile:SeeTag12.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('wait') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_RPAREN(')') PsiWhiteSpace('\n ') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag14.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag14.txt index 9d930ec9c238..08f90474c3a7 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag14.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag14.txt @@ -29,7 +29,7 @@ PsiJavaFile:SeeTag14.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('append') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:char[] PsiTypeElement:char diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag15.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag15.txt index a535a82cc44f..fa79b853c1a4 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag15.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag15.txt @@ -29,7 +29,7 @@ PsiJavaFile:SeeTag15.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('append') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:java.lang.Object PsiJavaCodeReferenceElement:java.lang.Object diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag16.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag16.txt index d7f1d3d5157a..3d1fa26a8169 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag16.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag16.txt @@ -19,7 +19,7 @@ PsiJavaFile:SeeTag16.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('equals') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:int PsiKeyword:int('int') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag3.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag3.txt index a2a28c9a945a..f018c5af50c1 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag3.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag3.txt @@ -19,7 +19,7 @@ PsiJavaFile:SeeTag3.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('equals') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:Object PsiJavaCodeReferenceElement:Object diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag5.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag5.txt index 977e65124359..9903e7c37d6b 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag5.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag5.txt @@ -29,7 +29,7 @@ PsiJavaFile:SeeTag5.java PsiDocToken:DOC_TAG_VALUE_SHARP_TOKEN('#') PsiDocToken:DOC_TAG_VALUE_TOKEN('wait') PsiDocToken:DOC_TAG_VALUE_LPAREN('(') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiElement(DOC_TYPE_HOLDER) PsiTypeElement:long PsiKeyword:long('long') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag9.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag9.txt index 75968a87205e..7b2b10a6a7ce 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag9.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/SeeTag9.txt @@ -15,16 +15,16 @@ PsiJavaFile:SeeTag9.java PsiIdentifier:equals('equals') PsiReferenceParameterList - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_LPAREN('(') PsiElement(DOC_REFERENCE_HOLDER) PsiKeyword:long('long') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_COMMA(',') PsiWhiteSpace(' ') PsiElement(DOC_REFERENCE_HOLDER) PsiKeyword:long('long') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_RPAREN(')') PsiWhiteSpace('\n ') PsiDocToken:DOC_COMMENT_END('*/') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/Tag2.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/Tag2.txt index 45c260fa5f51..83308bc7bd6b 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/Tag2.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/Tag2.txt @@ -23,7 +23,7 @@ PsiJavaFile:Tag2.java PsiDocTag:@return PsiDocToken:DOC_TAG_NAME('@return') PsiWhiteSpace(' ') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_TOKEN('value') PsiWhiteSpace(' ') PsiDocToken:DOC_COMMENT_DATA('value') diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/Tag5.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/Tag5.txt index eb44d58a94e9..c6a9b80b47b6 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/Tag5.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/Tag5.txt @@ -10,7 +10,7 @@ PsiJavaFile:Tag5.java PsiDocTag:@ejb:bean PsiDocToken:DOC_TAG_NAME('@ejb:bean') PsiWhiteSpace(' ') - PsiElement(DOC_TAG_VALUE_TOKEN) + PsiElement(DOC_TAG_VALUE_ELEMENT) PsiDocToken:DOC_TAG_VALUE_TOKEN('this') PsiWhiteSpace(' ') PsiDocToken:DOC_COMMENT_DATA('is an EJB ') diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java index b8c5012f562e..768679bdb501 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java @@ -62,5 +62,6 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas public void testIDEA84489() throws Throwable { doTest(); } public void testComparingToNotNullShouldNotAffectNullity() throws Throwable { doTest(); } + public void testStringTernaryAlwaysTrue() throws Throwable { doTest(); } } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java index 16fb8dd3c01c..63fcd6b60215 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.psi.formatter.java; import com.intellij.openapi.application.ApplicationManager; @@ -529,12 +544,12 @@ public class JavaFormatterTest extends AbstractJavaFormatterTest { public void testJavaDocLinksWithParameterNames() throws Exception { // See IDEADEV-8332 doTextTest("/**\n" + - "* @return if ( x1 == x1 ) then retrun {@link #cmp(String y1,int y2)}\n" + + "* @return if ( x1 == x1 ) then return {@link #cmp(String y1,int y2)}\n" + "* otherwise return {@link #cmp(int x1,int x2)}\n" + "*/\n" + "class X {\n" + "}\n", "/**\n" + - " * @return if ( x1 == x1 ) then retrun {@link #cmp(String y1, int y2)}\n" + + " * @return if ( x1 == x1 ) then return {@link #cmp(String y1, int y2)}\n" + " * otherwise return {@link #cmp(int x1, int x2)}\n" + " */\n" + "class X {\n" + diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index be62585412c8..f90f00941c1f 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -86,7 +86,7 @@ public class Mappings { myChangedFiles = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); myDeletedClasses = new HashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); myDeltaIsTransient = base.myDeltaIsTransient; - myRootDir = new File(FileUtil.toSystemIndependentName(base.myRootDir.getAbsolutePath()) + File.separatorChar + "delta"); + myRootDir = new File(FileUtil.toSystemIndependentName(base.myRootDir.getAbsolutePath()) + File.separatorChar + "myDelta"); myContext = base.myContext; myInitName = myContext.get(""); myEmptyName = myContext.get(""); @@ -232,7 +232,6 @@ public class Mappings { private final List myPostPasses; - private void addPostPass(final PostPass p) { myPostPasses.add(p); } @@ -672,7 +671,7 @@ public class Mappings { final File theFile = new File(myContext.getValue(depFile)); if (filter == null || filter.accept(theFile)) { - affectedFiles.add(theFile); + affectedFiles.add(theFile); } } return true; @@ -846,773 +845,270 @@ public class Mappings { boolean accept(File file); } - public boolean differentiate(final Mappings delta, - final Collection removed, - final Collection filesToCompile, - final Collection compiledFiles, - final Collection affectedFiles, - final DependentFilesFilter filter, - @Nullable final Callbacks.ConstantAffectionResolver constantSearch) { - synchronized (myLock) { + private class Differential { + final int DESPERATE_MASK = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL; - class DelayedWorks { - class Triple { - final int owner; - final FieldRepr field; - @Nullable - final Future affection; + final Mappings myDelta; + final Collection myRemoved; + final Collection myFilesToCompile; + final Collection myCompiledFiles; + final Collection myAffectedFiles; + final DependentFilesFilter myFilter; + @Nullable final Callbacks.ConstantAffectionResolver myConstantSearch; + final DelayedWorks myDelayedWorks; - private Triple(final int owner, final FieldRepr field, @Nullable final Future affection) { - this.owner = owner; - this.field = field; - this.affection = affection; - } + final Util myUpdated; + final Util mySelf; + final Util myOriginal; - Callbacks.ConstantAffection getAffection() { - try { - return affection != null ? affection.get() : Callbacks.ConstantAffection.EMPTY; - } - catch (Exception e) { - throw new RuntimeException(e); - } - } + private class DelayedWorks { + class Triple { + final int owner; + final FieldRepr field; + @Nullable + final Future affection; + + private Triple(final int owner, final FieldRepr field, @Nullable final Future affection) { + this.owner = owner; + this.field = field; + this.affection = affection; } - final Collection myQueue = new LinkedList(); - - void addConstantWork(final int ownerClass, final FieldRepr changedField, final boolean isRemoved, boolean accessChanged) { - final Future future; - if (constantSearch == null) { - future = null; + Callbacks.ConstantAffection getAffection() { + try { + return affection != null ? affection.get() : Callbacks.ConstantAffection.EMPTY; } - else { - final String className = myContext.getValue(ownerClass); - final String fieldName = myContext.getValue(changedField.name); - future = constantSearch.request(className.replace('/', '.'), fieldName, changedField.access, isRemoved, accessChanged); + catch (Exception e) { + throw new RuntimeException(e); } - myQueue.add(new Triple(ownerClass, changedField, future)); - } - - boolean doWork(final Collection affectedFiles) { - if (!myQueue.isEmpty()) { - debug("Starting delayed works."); - - for (final Triple t : myQueue) { - final Callbacks.ConstantAffection affection = t.getAffection(); - - debug("Class: ", t.owner); - debug("Field: ", t.field.name); - - if (!affection.isKnown()) { - debug("No external dependency information available."); - debug("Trying to soften non-incremental decision."); - if (!incrementalDecision(t.owner, t.field, affectedFiles, filter)) { - debug("No luck."); - debug("End of delayed work, returning false."); - return false; - } - } - else { - debug("External dependency information retrieved."); - affectedFiles.addAll(affection.getAffectedFiles()); - } - } - - debug("End of delayed work, returning true."); - } - return true; } } - final DelayedWorks works = new DelayedWorks(); + final Collection myQueue = new LinkedList(); - debug("Begin of Differentiate:"); + void addConstantWork(final int ownerClass, final FieldRepr changedField, final boolean isRemoved, boolean accessChanged) { + final Future future; + if (myConstantSearch == null) { + future = null; + } + else { + final String className = myContext.getValue(ownerClass); + final String fieldName = myContext.getValue(changedField.name); + future = myConstantSearch.request(className.replace('/', '.'), fieldName, changedField.access, isRemoved, accessChanged); + } + myQueue.add(new Triple(ownerClass, changedField, future)); + } - delta.runPostPasses(); - delta.compensateRemovedContent(filesToCompile); + boolean doWork(final Collection affectedFiles) { + if (!myQueue.isEmpty()) { + debug("Starting delayed works."); - final Util u = new Util(delta); - final Util self = new Util(this); - final Util o = new Util(); + for (final Triple t : myQueue) { + final Callbacks.ConstantAffection affection = t.getAffection(); - if (removed != null) { - for (String file : removed) { + debug("Class: ", t.owner); + debug("Field: ", t.field.name); + + if (!affection.isKnown()) { + debug("No external dependency information available."); + debug("Trying to soften non-incremental decision."); + if (!incrementalDecision(t.owner, t.field, affectedFiles, myFilter)) { + debug("No luck."); + debug("End of delayed work, returning false."); + return false; + } + } + else { + debug("External dependency information retrieved."); + affectedFiles.addAll(affection.getAffectedFiles()); + } + } + + debug("End of delayed work, returning true."); + } + return true; + } + } + + private class FileClasses { + final int fileName; + final Set fileClasses; + + FileClasses(int fileName, Collection fileClasses) { + this.fileName = fileName; + this.fileClasses = new HashSet(fileClasses); + } + } + + private class DiffState { + final public TIntHashSet dependants = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); + + final public Set affectedUsages = new HashSet(); + final public Set annotationQuery = new HashSet(); + final public Map usageConstraints = new HashMap(); + + final Difference.Specifier classDiff; + + private DiffState(Difference.Specifier classDiff) { + this.classDiff = classDiff; + } + } + + private Differential(final Mappings delta, + final Collection removed, + final Collection filesToCompile, + final Collection compiledFiles, + final Collection affectedFiles, + final DependentFilesFilter filter, + @Nullable final Callbacks.ConstantAffectionResolver constantSearch) { + this.myDelta = delta; + this.myRemoved = removed; + this.myFilesToCompile = filesToCompile; + this.myCompiledFiles = compiledFiles; + this.myAffectedFiles = affectedFiles; + this.myFilter = filter; + this.myConstantSearch = constantSearch; + + myDelayedWorks = new DelayedWorks(); + + myUpdated = new Util(myDelta); + mySelf = new Util(Mappings.this); + myOriginal = new Util(); + } + + private void processDisappearedClasses() { + myDelta.runPostPasses(); + myDelta.compensateRemovedContent(myFilesToCompile); + + if (myRemoved != null) { + for (String file : myRemoved) { final Collection classes = mySourceFileToClasses.get(myContext.get(file)); if (classes != null) { for (ClassRepr c : classes) { debug("Affecting usages of removed class ", c.name); - u.affectAll(c.name, affectedFiles, filter); + myUpdated.affectAll(c.name, myAffectedFiles, myFilter); } } } } + } - class FileClasses { - final int fileName; - final Set fileClasses; + private void processAddedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { + debug("Processing added methods: "); + for (final MethodRepr m : diff.methods().added()) { + debug("Method: ", m.name); - FileClasses(int fileName, Collection fileClasses) { - this.fileName = fileName; - this.fileClasses = new HashSet(fileClasses); + if (it.isAnnotation()) { + debug("Class is annotation, skipping method analysis"); + continue; } - } - final List newClasses = new ArrayList(); - delta.mySourceFileToClasses.forEachEntry(new TIntObjectProcedure>() { - @Override - public boolean execute(int fileName, Collection classes) { - newClasses.add(new FileClasses(fileName, classes)); - return true; + if ((it.access & Opcodes.ACC_INTERFACE) > 0 || + (it.access & Opcodes.ACC_ABSTRACT) > 0 || + (m.access & Opcodes.ACC_ABSTRACT) > 0) { + debug("Class is abstract, or is interface, or added method in abstract => affecting all subclasses"); + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.affectedUsages, state.dependants, false); } - }); - for (final FileClasses compiledFile : newClasses) { - final int fileName = compiledFile.fileName; - final Set classes = compiledFile.fileClasses; - final Set pastClasses = (Set)mySourceFileToClasses.get(fileName); - final TIntHashSet dependants = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); + TIntHashSet propagated = null; - final Set affectedUsages = new HashSet(); - final Set annotationQuery = new HashSet(); - final Map usageConstraints = new HashMap(); + if ((m.access & Opcodes.ACC_PRIVATE) == 0 && m.name != myInitName) { + final ClassRepr oldIt = getReprByName(it.name); - final Difference.Specifier classDiff = Difference.make(pastClasses, classes); + if (oldIt != null && mySelf.findOverridenMethods(m, oldIt).size() > 0) { - debug("Processing changed classes:"); - for (final Pair changed : classDiff.changed()) { - final ClassRepr it = changed.first; - final ClassRepr.Diff diff = (ClassRepr.Diff)changed.second; + } + else { + if (m.argumentTypes.length > 0) { + propagated = myUpdated.propagateMethodAccess(m.name, it.name); + debug("Conservative case on overriding methods, affecting method usages"); + myUpdated.affectMethodUsages(m, propagated, m.createMetaUsage(myContext, it.name), state.affectedUsages, state.dependants); + } + } + } - self.appendDependents(it, dependants); + if ((m.access & Opcodes.ACC_PRIVATE) == 0) { + final Collection> affectedMethods = myUpdated.findAllMethodsBySpecificity(m, it); + final MethodRepr.Predicate overrides = MethodRepr.equalByJavaRules(m); - delta.addChangedClass(it.name); - - debug("Changed: ", it.name); - - final int addedModifiers = diff.addedModifiers(); - - final boolean superClassChanged = (diff.base() & Difference.SUPERCLASS) > 0; - final boolean interfacesChanged = !diff.interfaces().unchanged(); - final boolean signatureChanged = (diff.base() & Difference.SIGNATURE) > 0; - - if (superClassChanged || interfacesChanged || signatureChanged) { - debug("Superclass changed: ", superClassChanged); - debug("Interfaces changed: ", interfacesChanged); - debug("Signature changed ", signatureChanged); - - final boolean extendsChanged = superClassChanged && !diff.extendsAdded(); - final boolean interfacesRemoved = interfacesChanged && !diff.interfaces().removed().isEmpty(); - - debug("Extends changed: ", extendsChanged); - debug("Interfaces removed: ", interfacesRemoved); - - u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, extendsChanged || interfacesRemoved || signatureChanged); + if (propagated == null) { + propagated = myUpdated.propagateMethodAccess(m.name, it.name); } - if ((diff.addedModifiers() & Opcodes.ACC_INTERFACE) > 0 || (diff.removedModifiers() & Opcodes.ACC_INTERFACE) > 0) { - debug("Class-to-interface or interface-to-class conversion detected, added class usage to affected usages"); - affectedUsages.add(it.createUsage()); - } + final Collection lessSpecific = it.findMethods(myUpdated.lessSpecific(m)); - if (it.isAnnotation() && it.policy == RetentionPolicy.SOURCE) { - debug("Annotation, retention policy = SOURCE => a switch to non-incremental mode requested"); - if (!incrementalDecision(it.outerClassName, it, affectedFiles, filter)) { - debug("End of Differentiate, returning false"); - return false; + for (final MethodRepr mm : lessSpecific) { + if (!mm.equals(m)) { + debug("Found less specific method, affecting method usages"); + myUpdated.affectMethodUsages(mm, propagated, mm.createUsage(myContext, it.name), state.affectedUsages, state.dependants); } } - if ((addedModifiers & Opcodes.ACC_PROTECTED) > 0) { - debug("Introduction of 'protected' modifier detected, adding class usage + inheritance constraint to affected usages"); - final UsageRepr.Usage usage = it.createUsage(); + debug("Processing affected by specificity methods"); + for (final Pair p : affectedMethods) { + final MethodRepr mm = p.first; + final ClassRepr cc = p.second; - affectedUsages.add(usage); - usageConstraints.put(usage, u.new InheritanceConstraint(it.name)); - } + if (cc == myMockClass) { - if (diff.packageLocalOn()) { - debug("Introduction of 'package local' access detected, adding class usage + package constraint to affected usages"); - final UsageRepr.Usage usage = it.createUsage(); - - affectedUsages.add(usage); - usageConstraints.put(usage, u.new PackageConstraint(it.getPackageName())); - } - - if ((addedModifiers & Opcodes.ACC_FINAL) > 0 || (addedModifiers & Opcodes.ACC_PRIVATE) > 0) { - debug("Introduction of 'private' or 'final' modifier(s) detected, adding class usage to affected usages"); - affectedUsages.add(it.createUsage()); - } - - if ((addedModifiers & Opcodes.ACC_ABSTRACT) > 0 || (addedModifiers & Opcodes.ACC_STATIC) > 0) { - debug("Introduction of 'abstract' or 'static' modifier(s) detected, adding class new usage to affected usages"); - affectedUsages.add(UsageRepr.createClassNewUsage(myContext, it.name)); - } - - if (it.isAnnotation()) { - debug("Class is annotation, performing annotation-specific analysis"); - - if (diff.retentionChanged()) { - debug("Retention policy change detected, adding class usage to affected usages"); - affectedUsages.add(it.createUsage()); } else { - final Collection removedtargets = diff.targets().removed(); + final Option inheritorOf = mySelf.isInheritorOf(cc.name, it.name); - if (removedtargets.contains(ElemType.LOCAL_VARIABLE)) { - debug("Removed target contains LOCAL_VARIABLE => a switch to non-incremental mode requested"); - if (!incrementalDecision(it.outerClassName, it, affectedFiles, filter)) { - debug("End of Differentiate, returning false"); - return false; + debug("Method: ", mm.name); + debug("Class : ", cc.name); + + if (overrides.satisfy(mm) && inheritorOf.isValue() && inheritorOf.value()) { + debug("Current method overrides that found"); + + final int file = myClassToSourceFile.get(cc.name); + + if (file > 0) { + final String f = myContext.getValue(file); + debug("Affecting file ", f); + myAffectedFiles.add(new File(f)); } } - - if (!removedtargets.isEmpty()) { - debug("Removed some annotation targets, adding annotation query"); - annotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr - .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), null, EnumSet.copyOf(removedtargets))); - } - - for (final MethodRepr m : diff.methods().added()) { - if (!m.hasValue()) { - debug("Added method with no default value: ", m.name); - debug("Adding class usage to affected usages"); - affectedUsages.add(it.createUsage()); - } - } - } - - debug("End of annotation-specific analysis"); - } - - debug("Processing added methods: "); - for (final MethodRepr m : diff.methods().added()) { - debug("Method: ", m.name); - - if (it.isAnnotation()) { - debug("Class is annotation, skipping method analysis"); - continue; - } - - if ((it.access & Opcodes.ACC_INTERFACE) > 0 || - (it.access & Opcodes.ACC_ABSTRACT) > 0 || - (m.access & Opcodes.ACC_ABSTRACT) > 0) { - debug("Class is abstract, or is interface, or added method in abstract => affecting all subclasses"); - u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false); - } - - TIntHashSet propagated = null; - - if ((m.access & Opcodes.ACC_PRIVATE) == 0 && m.name != myInitName) { - final ClassRepr oldIt = getReprByName(it.name); - - if (oldIt != null && self.findOverridenMethods(m, oldIt).size() > 0) { - - } else { - if (m.argumentTypes.length > 0) { - propagated = u.propagateMethodAccess(m.name, it.name); - debug("Conservative case on overriding methods, affecting method usages"); - u.affectMethodUsages(m, propagated, m.createMetaUsage(myContext, it.name), affectedUsages, dependants); - } - } - } + debug("Current method does not override that found"); - if ((m.access & Opcodes.ACC_PRIVATE) == 0) { - final Collection> affectedMethods = u.findAllMethodsBySpecificity(m, it); - final MethodRepr.Predicate overrides = MethodRepr.equalByJavaRules(m); + final TIntHashSet yetPropagated = mySelf.propagateMethodAccess(mm.name, it.name); - if (propagated == null) { - propagated = u.propagateMethodAccess(m.name, it.name); - } - - final Collection lessSpecific = it.findMethods(u.lessSpecific(m)); - - for (final MethodRepr mm : lessSpecific) { - if (!mm.equals(m)) { - debug("Found less specific method, affecting method usages"); - u.affectMethodUsages(mm, propagated, mm.createUsage(myContext, it.name), affectedUsages, dependants); - } - } - - debug("Processing affected by specificity methods"); - for (final Pair p : affectedMethods) { - final MethodRepr mm = p.first; - final ClassRepr cc = p.second; - - if (cc == myMockClass) { - - } - else { - final Option inheritorOf = self.isInheritorOf(cc.name, it.name); - - debug("Method: ", mm.name); - debug("Class : ", cc.name); - - if (overrides.satisfy(mm) && inheritorOf.isValue() && inheritorOf.value()) { - debug("Current method overrides that found"); - - final int file = myClassToSourceFile.get(cc.name); - - if (file > 0) { - final String f = myContext.getValue(file); - debug("Affecting file ", f); - affectedFiles.add(new File(f)); - } - } - else { - debug("Current method does not override that found"); - - final TIntHashSet yetPropagated = self.propagateMethodAccess(mm.name, it.name); - - if (inheritorOf.isValue() && inheritorOf.value()) { - final TIntHashSet deps = myClassToClassDependency.get(cc.name); - - if (deps != null) { - addAll(dependants, deps); - } - - u.affectMethodUsages(mm, yetPropagated, mm.createUsage(myContext, cc.name), affectedUsages, dependants); - } - - debug("Affecting method usages for that found"); - u.affectMethodUsages(mm, yetPropagated, mm.createUsage(myContext, it.name), affectedUsages, dependants); - } - } - } - - final TIntHashSet subClasses = getAllSubclasses(it.name); - - if (subClasses != null) { - subClasses.forEach(new TIntProcedure() { - @Override - public boolean execute(int subClass) { - final ClassRepr r = u.reprByName(subClass); - final int sourceFileName = myClassToSourceFile.get(subClass); - - if (r != null && sourceFileName > 0) { - final int outerClass = r.outerClassName; - - if (u.methodVisible(outerClass, m)) { - final String f = myContext.getValue(sourceFileName); - debug("Affecting file due to local overriding: ", f); - affectedFiles.add(new File(f)); - } - } - return true; - } - }); - } - } - } - debug("End of added methods processing"); - - debug("Processing removed methods:"); - for (final MethodRepr m : diff.methods().removed()) { - debug("Method ", m.name); - - final Collection> overridenMethods = u.findOverridenMethods(m, it); - final TIntHashSet propagated = u.propagateMethodAccess(m.name, it.name); - - if (overridenMethods.size() == 0) { - debug("No overridden methods found, affecting method usages"); - u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), affectedUsages, dependants); - } - else { - boolean clear = true; - - loop: - for (final Pair overriden : overridenMethods) { - final MethodRepr mm = overriden.first; - - if (mm == myMockMethod || !mm.type.equals(m.type) || !empty(mm.signature) || !empty(m.signature)) { - clear = false; - break loop; - } - } - - if (!clear) { - debug("No clearly overridden methods found, affecting method usages"); - u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), affectedUsages, dependants); - } - } - - final Collection> overriding = u.findOverridingMethods(m, it, false); - - for (final Pair p : overriding) { - final int fName = myClassToSourceFile.get(p.second.name); - debug("Affecting file by overriding: ", fName); - affectedFiles.add(new File(myContext.getValue(fName))); - } - - if ((m.access & Opcodes.ACC_ABSTRACT) == 0) { - propagated.forEach(new TIntProcedure() { - @Override - public boolean execute(int p) { - if (p != it.name) { - final ClassRepr s = u.reprByName(p); - - if (s != null) { - final Collection> overridenInS = u.findOverridenMethods(m, s); - - overridenInS.addAll(overridenMethods); - - boolean allAbstract = true; - boolean visited = false; - - for (final Pair pp : overridenInS) { - final ClassRepr cc = pp.second; - - if (cc == myMockClass) { - visited = true; - continue; - } - - if (cc.name == it.name) { - continue; - } - - visited = true; - allAbstract = ((pp.first.access & Opcodes.ACC_ABSTRACT) > 0) || ((cc.access & Opcodes.ACC_INTERFACE) > 0); - - if (!allAbstract) { - break; - } - } - - if (allAbstract && visited) { - final int source = myClassToSourceFile.get(p); - - if (source > 0) { - final String f = myContext.getValue(source); - debug( - "Removed method is not abstract & overrides some abstract method which is not then over-overriden in subclass ", - p); - debug("Affecting subclass source file ", f); - affectedFiles.add(new File(f)); - } - } - } - } - return true; - } - }); - } - } - debug("End of removed methods processing"); - - debug("Processing changed methods:"); - for (final Pair mr : diff.methods().changed()) { - final MethodRepr m = mr.first; - final MethodRepr.Diff d = (MethodRepr.Diff)mr.second; - final boolean throwsChanged = (d.exceptions().added().size() > 0) || (d.exceptions().changed().size() > 0); - - debug("Method: ", m.name); - - if (it.isAnnotation()) { - if (d.defaultRemoved()) { - debug("Class is annotation, default value is removed => adding annotation query"); - final TIntHashSet l = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); - l.add(m.name); - annotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr - .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), l, null)); - } - } - else if (d.base() != Difference.NONE || throwsChanged) { - final TIntHashSet propagated = u.propagateMethodAccess(m.name, it.name); - - boolean affected = false; - boolean constrained = false; - - final Set usages = new HashSet(); - - if (d.packageLocalOn()) { - debug("Method became package-local, affecting method usages outside the package"); - u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants); - - for (final UsageRepr.Usage usage : usages) { - usageConstraints.put(usage, u.new InheritanceConstraint(it.name)); - } - - affectedUsages.addAll(usages); - affected = true; - constrained = true; - } - - if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0 || throwsChanged) { - if (!affected) { - debug("Return type, throws list or signature changed --- affecting method usages"); - u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants); - affectedUsages.addAll(usages); - } - } - else if ((d.base() & Difference.ACCESS) > 0) { - if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0 || - (d.removedModifiers() & Opcodes.ACC_STATIC) > 0 || - (d.addedModifiers() & Opcodes.ACC_PRIVATE) > 0) { - if (!affected) { - debug("Added static or private specifier or removed static specifier --- affecting method usages"); - u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants); - affectedUsages.addAll(usages); - } - - if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0) { - debug("Added static specifier --- affecting subclasses"); - u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false); - } - } - else { - if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0 || - (d.addedModifiers() & Opcodes.ACC_PUBLIC) > 0 || - (d.addedModifiers() & Opcodes.ACC_ABSTRACT) > 0) { - debug("Added final, public or abstract specifier --- affecting subclasses"); - u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false); - } - - if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0 && !((d.removedModifiers() & Opcodes.ACC_PRIVATE) > 0)) { - if (!constrained) { - debug("Added public or package-local method became protected --- affect method usages with protected constraint"); - if (!affected) { - u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants); - affectedUsages.addAll(usages); - } - - for (final UsageRepr.Usage usage : usages) { - usageConstraints.put(usage, u.new InheritanceConstraint(it.name)); - } - } - } - } - } - } - } - debug("End of changed methods processing"); - - final int mask = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL; - - debug("Processing added fields"); - for (final FieldRepr f : diff.fields().added()) { - debug("Field: ", f.name); - - final boolean fPrivate = (f.access & Opcodes.ACC_PRIVATE) > 0; - final boolean fProtected = (f.access & Opcodes.ACC_PROTECTED) > 0; - final boolean fPublic = (f.access & Opcodes.ACC_PUBLIC) > 0; - final boolean fPLocal = !fPrivate && !fProtected && !fPublic; - - if (!fPrivate) { - final TIntHashSet subClasses = getAllSubclasses(it.name); - subClasses.forEach(new TIntProcedure() { - @Override - public boolean execute(int subClass) { - final ClassRepr r = u.reprByName(subClass); - final int sourceFileName = myClassToSourceFile.get(subClass); - - if (r != null && sourceFileName > 0) { - if (r.isLocal) { - debug( - "Affecting local subclass (introduced field can potentially hide surrounding method parameters/local variables): ", - sourceFileName); - affectedFiles.add(new File(myContext.getValue(sourceFileName))); - } - else { - final int outerClass = r.outerClassName; - - if (!empty(outerClass) && u.fieldVisible(outerClass, f)) { - debug("Affecting inner subclass (introduced field can potentially hide surrounding class fields): ", - sourceFileName); - affectedFiles.add(new File(myContext.getValue(sourceFileName))); - } - } - } - - debug("Affecting field usages referenced from subclass ", subClass); - final TIntHashSet propagated = u.propagateFieldAccess(f.name, subClass); - u.affectFieldUsages(f, propagated, f.createUsage(myContext, subClass), affectedUsages, dependants); - - final TIntHashSet deps = myClassToClassDependency.get(subClass); + if (inheritorOf.isValue() && inheritorOf.value()) { + final TIntHashSet deps = myClassToClassDependency.get(cc.name); if (deps != null) { - addAll(dependants, deps); - } - return true; - } - }); - } - - final Collection> overridden = u.findOverridenFields(f, it); - - for (final Pair p : overridden) { - final FieldRepr ff = p.first; - final ClassRepr cc = p.second; - - final boolean ffPrivate = (ff.access & Opcodes.ACC_PRIVATE) > 0; - final boolean ffProtected = (ff.access & Opcodes.ACC_PROTECTED) > 0; - final boolean ffPublic = (ff.access & Opcodes.ACC_PUBLIC) > 0; - final boolean ffPLocal = Difference.isPackageLocal(ff.access); - - if (!ffPrivate) { - final TIntHashSet propagated = o.propagateFieldAccess(ff.name, cc.name); - final Set localUsages = new HashSet(); - - debug("Affecting usages of overridden field in class ", cc.name); - u.affectFieldUsages(ff, propagated, ff.createUsage(myContext, cc.name), localUsages, dependants); - - if (fPrivate || (fPublic && (ffPublic || ffPLocal)) || (fProtected && ffProtected) || (fPLocal && ffPLocal)) { - - } - else { - Util.UsageConstraint constaint; - - if ((ffProtected && fPublic) || (fProtected && ffPublic) || (ffPLocal && fProtected)) { - constaint = u.new NegationConstraint(u.new InheritanceConstraint(cc.name)); - } - else if (ffPublic && ffPLocal) { - constaint = u.new NegationConstraint(u.new PackageConstraint(cc.getPackageName())); - } - else { - constaint = u.new IntersectionConstraint(u.new NegationConstraint(u.new InheritanceConstraint(cc.name)), - u.new NegationConstraint(u.new PackageConstraint(cc.getPackageName()))); + addAll(state.dependants, deps); } - for (final UsageRepr.Usage usage : localUsages) { - usageConstraints.put(usage, constaint); - } + myUpdated + .affectMethodUsages(mm, yetPropagated, mm.createUsage(myContext, cc.name), state.affectedUsages, state.dependants); } - affectedUsages.addAll(localUsages); + debug("Affecting method usages for that found"); + myUpdated + .affectMethodUsages(mm, yetPropagated, mm.createUsage(myContext, it.name), state.affectedUsages, state.dependants); } } } - debug("End of added fields processing"); - debug("Processing removed fields:"); - for (final FieldRepr f : diff.fields().removed()) { - debug("Field: ", f.name); + final TIntHashSet subClasses = getAllSubclasses(it.name); - if ((f.access & Opcodes.ACC_PRIVATE) == 0 && (f.access & mask) == mask && f.hasValue()) { - debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested"); - if (constantSearch != null) { - works.addConstantWork(it.name, f, true, false); - } - else { - if (!incrementalDecision(it.name, f, affectedFiles, filter)) { - debug("End of Differentiate, returning false"); - return false; - } - } - } - - final TIntHashSet propagated = u.propagateFieldAccess(f.name, it.name); - u.affectFieldUsages(f, propagated, f.createUsage(myContext, it.name), affectedUsages, dependants); - } - debug("End of removed fields processing"); - - debug("Processing changed fields:"); - for (final Pair f : diff.fields().changed()) { - final Difference d = f.second; - final FieldRepr field = f.first; - - debug("Field: ", field.name); - - if ((field.access & Opcodes.ACC_PRIVATE) == 0 && (field.access & mask) == mask) { - final int changedModifiers = d.addedModifiers() | d.removedModifiers(); - final boolean harmful = (changedModifiers & (Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) > 0; - final boolean accessChanged = (changedModifiers & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) > 0; - final boolean valueChanged = (d.base() & Difference.VALUE) > 0 && d.hadValue(); - - if (harmful || valueChanged || (accessChanged && !d.weakedAccess())) { - debug("Inline field changed it's access or value => a switch to non-incremental mode requested"); - if (constantSearch != null) { - works.addConstantWork(it.name, field, false, accessChanged); - } - else { - if (!incrementalDecision(it.name, field, affectedFiles, filter)) { - debug("End of Differentiate, returning false"); - return false; - } - } - } - } - - if (d.base() != Difference.NONE) { - final TIntHashSet propagated = u.propagateFieldAccess(field.name, it.name); - - if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0) { - debug("Type or signature changed --- affecting field usages"); - u.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), affectedUsages, dependants); - } - else if ((d.base() & Difference.ACCESS) > 0) { - if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0 || - (d.removedModifiers() & Opcodes.ACC_STATIC) > 0 || - (d.addedModifiers() & Opcodes.ACC_PRIVATE) > 0 || - (d.addedModifiers() & Opcodes.ACC_VOLATILE) > 0) { - debug("Added/removed static modifier or added private/volatile modifier --- affecting field usages"); - u.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), affectedUsages, dependants); - } - else { - boolean affected = false; - final Set usages = new HashSet(); - - if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0) { - debug("Added final modifier --- affecting field assign usages"); - u.affectFieldUsages(field, propagated, field.createAssignUsage(myContext, it.name), usages, dependants); - affectedUsages.addAll(usages); - affected = true; - } - - if ((d.removedModifiers() & Opcodes.ACC_PUBLIC) > 0) { - debug("Removed public modifier, affecting field usages with appropriate constraint"); - if (!affected) { - u.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), usages, dependants); - affectedUsages.addAll(usages); - } - - for (final UsageRepr.Usage usage : usages) { - if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0) { - usageConstraints.put(usage, u.new InheritanceConstraint(it.name)); - } - else { - usageConstraints.put(usage, u.new PackageConstraint(it.getPackageName())); - } - } - } - } - } - } - } - debug("End of changed fields processing"); - } - debug("End of changed classes processing"); - - debug("Processing removed classes:"); - for (final ClassRepr c : classDiff.removed()) { - delta.addDeletedClass(c); - self.appendDependents(c, dependants); - debug("Adding usages of class ", c.name); - affectedUsages.add(c.createUsage()); - } - debug("End of removed classes processing."); - - debug("Processing added classes:"); - for (final ClassRepr c : classDiff.added()) { - debug("Class name: ", c.name); - delta.addChangedClass(c.name); - - final TIntHashSet depClasses = myClassToClassDependency.get(c.name); - - if (depClasses != null) { - depClasses.forEach(new TIntProcedure() { + if (subClasses != null) { + subClasses.forEach(new TIntProcedure() { @Override - public boolean execute(int depClass) { - final int fName = myClassToSourceFile.get(depClass); + public boolean execute(int subClass) { + final ClassRepr r = myUpdated.reprByName(subClass); + final int sourceFileName = myClassToSourceFile.get(subClass); - if (fName > 0) { - final String f = myContext.getValue(fName); - final File theFile = new File(f); + if (r != null && sourceFileName > 0) { + final int outerClass = r.outerClassName; - if (filter.accept(theFile)) { - debug("Adding dependent file ", f); - affectedFiles.add(theFile); + if (myUpdated.methodVisible(outerClass, m)) { + final String f = myContext.getValue(sourceFileName); + debug("Affecting file due to local overriding: ", f); + myAffectedFiles.add(new File(f)); } } return true; @@ -1620,92 +1116,704 @@ public class Mappings { }); } } - debug("End of added classes processing."); + } + debug("End of added methods processing"); + } - debug("Checking dependent files:"); - final TIntHashSet dependentFiles = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); + private void processRemovedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { + debug("Processing removed methods:"); + for (final MethodRepr m : diff.methods().removed()) { + debug("Method ", m.name); - dependants.forEach(new TIntProcedure() { - @Override - public boolean execute(int depClass) { - final int file = myClassToSourceFile.get(depClass); - if (file > 0) { - dependentFiles.add(file); + final Collection> overridenMethods = myUpdated.findOverridenMethods(m, it); + final TIntHashSet propagated = myUpdated.propagateMethodAccess(m.name, it.name); + + if (overridenMethods.size() == 0) { + debug("No overridden methods found, affecting method usages"); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), state.affectedUsages, state.dependants); + } + else { + boolean clear = true; + + loop: + for (final Pair overriden : overridenMethods) { + final MethodRepr mm = overriden.first; + + if (mm == myMockMethod || !mm.type.equals(m.type) || !empty(mm.signature) || !empty(m.signature)) { + clear = false; + break loop; } - return true; - } - }); - - - filewise: - for (final int depFile : dependentFiles.toArray()) { // todo: avoid toArray()? - final File theFile = new File(myContext.getValue(depFile)); - - if (affectedFiles.contains(theFile) || compiledFiles.contains(theFile)) { - continue filewise; } - debug("Dependent file: ", depFile); - final Collection depClusters = mySourceFileToUsages.get(depFile); - if (depClusters != null) { - for (final UsageRepr.Cluster depCluster : depClusters) { - final Set depUsages = depCluster.getUsages(); - if (depUsages == null) { - continue; - } - final Set usages = new HashSet(depUsages); + if (!clear) { + debug("No clearly overridden methods found, affecting method usages"); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), state.affectedUsages, state.dependants); + } + } - usages.retainAll(affectedUsages); + final Collection> overriding = myUpdated.findOverridingMethods(m, it, false); - if (!usages.isEmpty()) { - for (UsageRepr.Usage usage : usages) { - final Util.UsageConstraint constraint = usageConstraints.get(usage); + for (final Pair p : overriding) { + final int fName = myClassToSourceFile.get(p.second.name); + debug("Affecting file by overriding: ", fName); + myAffectedFiles.add(new File(myContext.getValue(fName))); + } - if (constraint == null) { - debug("Added file with no constraints"); - affectedFiles.add(theFile); - continue filewise; + if ((m.access & Opcodes.ACC_ABSTRACT) == 0) { + propagated.forEach(new TIntProcedure() { + @Override + public boolean execute(int p) { + if (p != it.name) { + final ClassRepr s = myUpdated.reprByName(p); + + if (s != null) { + final Collection> overridenInS = myUpdated.findOverridenMethods(m, s); + + overridenInS.addAll(overridenMethods); + + boolean allAbstract = true; + boolean visited = false; + + for (final Pair pp : overridenInS) { + final ClassRepr cc = pp.second; + + if (cc == myMockClass) { + visited = true; + continue; + } + + if (cc.name == it.name) { + continue; + } + + visited = true; + allAbstract = ((pp.first.access & Opcodes.ACC_ABSTRACT) > 0) || ((cc.access & Opcodes.ACC_INTERFACE) > 0); + + if (!allAbstract) { + break; + } } - else { - final TIntHashSet residenceClasses = depCluster.getResidence(usage); - for (final int residentName : residenceClasses.toArray()) { - if (constraint.checkResidence(residentName)) { - debug("Added file with satisfied constraint"); - affectedFiles.add(theFile); - continue filewise; - } + + if (allAbstract && visited) { + final int source = myClassToSourceFile.get(p); + + if (source > 0) { + final String f = myContext.getValue(source); + debug( + "Removed method is not abstract & overrides some abstract method which is not then over-overriden in subclass ", + p); + debug("Affecting subclass source file ", f); + myAffectedFiles.add(new File(f)); } } } } + return true; + } + }); + } + } + debug("End of removed methods processing"); + } - if (annotationQuery.size() > 0) { - final Collection annotationUsages = mySourceFileToAnnotationUsages.get(depFile); + private void processChangedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { + debug("Processing changed methods:"); + for (final Pair mr : diff.methods().changed()) { + final MethodRepr m = mr.first; + final MethodRepr.Diff d = (MethodRepr.Diff)mr.second; + final boolean throwsChanged = (d.exceptions().added().size() > 0) || (d.exceptions().changed().size() > 0); - for (final UsageRepr.Usage usage : annotationUsages) { - for (final UsageRepr.AnnotationUsage query : annotationQuery) { - if (query.satisfies(usage)) { - debug("Added file due to annotation query"); - affectedFiles.add(theFile); + debug("Method: ", m.name); + + if (it.isAnnotation()) { + if (d.defaultRemoved()) { + debug("Class is annotation, default value is removed => adding annotation query"); + final TIntHashSet l = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); + l.add(m.name); + state.annotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr + .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), l, null)); + } + } + else if (d.base() != Difference.NONE || throwsChanged) { + final TIntHashSet propagated = myUpdated.propagateMethodAccess(m.name, it.name); + + boolean affected = false; + boolean constrained = false; + + final Set usages = new HashSet(); + + if (d.packageLocalOn()) { + debug("Method became package-local, affecting method usages outside the package"); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.dependants); + + for (final UsageRepr.Usage usage : usages) { + state.usageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); + } + + state.affectedUsages.addAll(usages); + affected = true; + constrained = true; + } + + if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0 || throwsChanged) { + if (!affected) { + debug("Return type, throws list or signature changed --- affecting method usages"); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.dependants); + state.affectedUsages.addAll(usages); + } + } + else if ((d.base() & Difference.ACCESS) > 0) { + if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0 || + (d.removedModifiers() & Opcodes.ACC_STATIC) > 0 || + (d.addedModifiers() & Opcodes.ACC_PRIVATE) > 0) { + if (!affected) { + debug("Added static or private specifier or removed static specifier --- affecting method usages"); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.dependants); + state.affectedUsages.addAll(usages); + } + + if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0) { + debug("Added static specifier --- affecting subclasses"); + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.affectedUsages, state.dependants, false); + } + } + else { + if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0 || + (d.addedModifiers() & Opcodes.ACC_PUBLIC) > 0 || + (d.addedModifiers() & Opcodes.ACC_ABSTRACT) > 0) { + debug("Added final, public or abstract specifier --- affecting subclasses"); + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.affectedUsages, state.dependants, false); + } + + if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0 && !((d.removedModifiers() & Opcodes.ACC_PRIVATE) > 0)) { + if (!constrained) { + debug("Added public or package-local method became protected --- affect method usages with protected constraint"); + if (!affected) { + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.dependants); + state.affectedUsages.addAll(usages); + } + + for (final UsageRepr.Usage usage : usages) { + state.usageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); + } + } + } + } + } + } + } + debug("End of changed methods processing"); + } + + private boolean processAddedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { + debug("Processing added fields"); + + for (final FieldRepr f : diff.fields().added()) { + debug("Field: ", f.name); + + final boolean fPrivate = (f.access & Opcodes.ACC_PRIVATE) > 0; + final boolean fProtected = (f.access & Opcodes.ACC_PROTECTED) > 0; + final boolean fPublic = (f.access & Opcodes.ACC_PUBLIC) > 0; + final boolean fPLocal = !fPrivate && !fProtected && !fPublic; + + if (!fPrivate) { + final TIntHashSet subClasses = getAllSubclasses(it.name); + subClasses.forEach(new TIntProcedure() { + @Override + public boolean execute(int subClass) { + final ClassRepr r = myUpdated.reprByName(subClass); + final int sourceFileName = myClassToSourceFile.get(subClass); + + if (r != null && sourceFileName > 0) { + if (r.isLocal) { + debug( + "Affecting local subclass (introduced field can potentially hide surrounding method parameters/local variables): ", + sourceFileName); + myAffectedFiles.add(new File(myContext.getValue(sourceFileName))); + } + else { + final int outerClass = r.outerClassName; + + if (!empty(outerClass) && myUpdated.fieldVisible(outerClass, f)) { + debug("Affecting inner subclass (introduced field can potentially hide surrounding class fields): ", + sourceFileName); + myAffectedFiles.add(new File(myContext.getValue(sourceFileName))); + } + } + } + + debug("Affecting field usages referenced from subclass ", subClass); + final TIntHashSet propagated = myUpdated.propagateFieldAccess(f.name, subClass); + myUpdated.affectFieldUsages(f, propagated, f.createUsage(myContext, subClass), state.affectedUsages, state.dependants); + + final TIntHashSet deps = myClassToClassDependency.get(subClass); + + if (deps != null) { + addAll(state.dependants, deps); + } + return true; + } + }); + } + + final Collection> overridden = myUpdated.findOverridenFields(f, it); + + for (final Pair p : overridden) { + final FieldRepr ff = p.first; + final ClassRepr cc = p.second; + + final boolean ffPrivate = (ff.access & Opcodes.ACC_PRIVATE) > 0; + final boolean ffProtected = (ff.access & Opcodes.ACC_PROTECTED) > 0; + final boolean ffPublic = (ff.access & Opcodes.ACC_PUBLIC) > 0; + final boolean ffPLocal = Difference.isPackageLocal(ff.access); + + if (!ffPrivate) { + final TIntHashSet propagated = myOriginal.propagateFieldAccess(ff.name, cc.name); + final Set localUsages = new HashSet(); + + debug("Affecting usages of overridden field in class ", cc.name); + myUpdated.affectFieldUsages(ff, propagated, ff.createUsage(myContext, cc.name), localUsages, state.dependants); + + if (fPrivate || (fPublic && (ffPublic || ffPLocal)) || (fProtected && ffProtected) || (fPLocal && ffPLocal)) { + + } + else { + Util.UsageConstraint constaint; + + if ((ffProtected && fPublic) || (fProtected && ffPublic) || (ffPLocal && fProtected)) { + constaint = myUpdated.new NegationConstraint(myUpdated.new InheritanceConstraint(cc.name)); + } + else if (ffPublic && ffPLocal) { + constaint = myUpdated.new NegationConstraint(myUpdated.new PackageConstraint(cc.getPackageName())); + } + else { + constaint = + myUpdated.new IntersectionConstraint(myUpdated.new NegationConstraint(myUpdated.new InheritanceConstraint(cc.name)), + myUpdated.new NegationConstraint( + myUpdated.new PackageConstraint(cc.getPackageName()))); + } + + for (final UsageRepr.Usage usage : localUsages) { + state.usageConstraints.put(usage, constaint); + } + } + + state.affectedUsages.addAll(localUsages); + } + } + } + debug("End of added fields processing"); + + return true; + } + + private boolean processRemovedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { + debug("Processing removed fields:"); + + for (final FieldRepr f : diff.fields().removed()) { + debug("Field: ", f.name); + + if ((f.access & Opcodes.ACC_PRIVATE) == 0 && (f.access & DESPERATE_MASK) == DESPERATE_MASK && f.hasValue()) { + debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested"); + if (myConstantSearch != null) { + myDelayedWorks.addConstantWork(it.name, f, true, false); + } + else { + if (!incrementalDecision(it.name, f, myAffectedFiles, myFilter)) { + debug("End of Differentiate, returning false"); + return false; + } + } + } + + final TIntHashSet propagated = myUpdated.propagateFieldAccess(f.name, it.name); + myUpdated.affectFieldUsages(f, propagated, f.createUsage(myContext, it.name), state.affectedUsages, state.dependants); + } + debug("End of removed fields processing"); + + return true; + } + + private boolean processChangedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { + debug("Processing changed fields:"); + + for (final Pair f : diff.fields().changed()) { + final Difference d = f.second; + final FieldRepr field = f.first; + + debug("Field: ", field.name); + + if ((field.access & Opcodes.ACC_PRIVATE) == 0 && (field.access & DESPERATE_MASK) == DESPERATE_MASK) { + final int changedModifiers = d.addedModifiers() | d.removedModifiers(); + final boolean harmful = (changedModifiers & (Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) > 0; + final boolean accessChanged = (changedModifiers & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) > 0; + final boolean valueChanged = (d.base() & Difference.VALUE) > 0 && d.hadValue(); + + if (harmful || valueChanged || (accessChanged && !d.weakedAccess())) { + debug("Inline field changed it's access or value => a switch to non-incremental mode requested"); + if (myConstantSearch != null) { + myDelayedWorks.addConstantWork(it.name, field, false, accessChanged); + } + else { + if (!incrementalDecision(it.name, field, myAffectedFiles, myFilter)) { + debug("End of Differentiate, returning false"); + return false; + } + } + } + } + + if (d.base() != Difference.NONE) { + final TIntHashSet propagated = myUpdated.propagateFieldAccess(field.name, it.name); + + if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0) { + debug("Type or signature changed --- affecting field usages"); + myUpdated.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), state.affectedUsages, state.dependants); + } + else if ((d.base() & Difference.ACCESS) > 0) { + if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0 || + (d.removedModifiers() & Opcodes.ACC_STATIC) > 0 || + (d.addedModifiers() & Opcodes.ACC_PRIVATE) > 0 || + (d.addedModifiers() & Opcodes.ACC_VOLATILE) > 0) { + debug("Added/removed static modifier or added private/volatile modifier --- affecting field usages"); + myUpdated + .affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), state.affectedUsages, state.dependants); + } + else { + boolean affected = false; + final Set usages = new HashSet(); + + if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0) { + debug("Added final modifier --- affecting field assign usages"); + myUpdated.affectFieldUsages(field, propagated, field.createAssignUsage(myContext, it.name), usages, state.dependants); + state.affectedUsages.addAll(usages); + affected = true; + } + + if ((d.removedModifiers() & Opcodes.ACC_PUBLIC) > 0) { + debug("Removed public modifier, affecting field usages with appropriate constraint"); + if (!affected) { + myUpdated.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), usages, state.dependants); + state.affectedUsages.addAll(usages); + } + + for (final UsageRepr.Usage usage : usages) { + if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0) { + state.usageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); + } + else { + state.usageConstraints.put(usage, myUpdated.new PackageConstraint(it.getPackageName())); + } + } + } + } + } + } + } + debug("End of changed fields processing"); + + return true; + } + + private boolean processChangedClasses(final DiffState state) { + debug("Processing changed classes:"); + for (final Pair changed : state.classDiff.changed()) { + final ClassRepr it = changed.first; + final ClassRepr.Diff diff = (ClassRepr.Diff)changed.second; + + mySelf.appendDependents(it, state.dependants); + + myDelta.addChangedClass(it.name); + + debug("Changed: ", it.name); + + final int addedModifiers = diff.addedModifiers(); + + final boolean superClassChanged = (diff.base() & Difference.SUPERCLASS) > 0; + final boolean interfacesChanged = !diff.interfaces().unchanged(); + final boolean signatureChanged = (diff.base() & Difference.SIGNATURE) > 0; + + if (superClassChanged || interfacesChanged || signatureChanged) { + debug("Superclass changed: ", superClassChanged); + debug("Interfaces changed: ", interfacesChanged); + debug("Signature changed ", signatureChanged); + + final boolean extendsChanged = superClassChanged && !diff.extendsAdded(); + final boolean interfacesRemoved = interfacesChanged && !diff.interfaces().removed().isEmpty(); + + debug("Extends changed: ", extendsChanged); + debug("Interfaces removed: ", interfacesRemoved); + + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.affectedUsages, state.dependants, + extendsChanged || interfacesRemoved || signatureChanged); + } + + if ((diff.addedModifiers() & Opcodes.ACC_INTERFACE) > 0 || (diff.removedModifiers() & Opcodes.ACC_INTERFACE) > 0) { + debug("Class-to-interface or interface-to-class conversion detected, added class usage to affected usages"); + state.affectedUsages.add(it.createUsage()); + } + + if (it.isAnnotation() && it.policy == RetentionPolicy.SOURCE) { + debug("Annotation, retention policy = SOURCE => a switch to non-incremental mode requested"); + if (!incrementalDecision(it.outerClassName, it, myAffectedFiles, myFilter)) { + debug("End of Differentiate, returning false"); + return false; + } + } + + if ((addedModifiers & Opcodes.ACC_PROTECTED) > 0) { + debug("Introduction of 'protected' modifier detected, adding class usage + inheritance constraint to affected usages"); + final UsageRepr.Usage usage = it.createUsage(); + + state.affectedUsages.add(usage); + state.usageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); + } + + if (diff.packageLocalOn()) { + debug("Introduction of 'package local' access detected, adding class usage + package constraint to affected usages"); + final UsageRepr.Usage usage = it.createUsage(); + + state.affectedUsages.add(usage); + state.usageConstraints.put(usage, myUpdated.new PackageConstraint(it.getPackageName())); + } + + if ((addedModifiers & Opcodes.ACC_FINAL) > 0 || (addedModifiers & Opcodes.ACC_PRIVATE) > 0) { + debug("Introduction of 'private' or 'final' modifier(s) detected, adding class usage to affected usages"); + state.affectedUsages.add(it.createUsage()); + } + + if ((addedModifiers & Opcodes.ACC_ABSTRACT) > 0 || (addedModifiers & Opcodes.ACC_STATIC) > 0) { + debug("Introduction of 'abstract' or 'static' modifier(s) detected, adding class new usage to affected usages"); + state.affectedUsages.add(UsageRepr.createClassNewUsage(myContext, it.name)); + } + + if (it.isAnnotation()) { + debug("Class is annotation, performing annotation-specific analysis"); + + if (diff.retentionChanged()) { + debug("Retention policy change detected, adding class usage to affected usages"); + state.affectedUsages.add(it.createUsage()); + } + else { + final Collection removedtargets = diff.targets().removed(); + + if (removedtargets.contains(ElemType.LOCAL_VARIABLE)) { + debug("Removed target contains LOCAL_VARIABLE => a switch to non-incremental mode requested"); + if (!incrementalDecision(it.outerClassName, it, myAffectedFiles, myFilter)) { + debug("End of Differentiate, returning false"); + return false; + } + } + + if (!removedtargets.isEmpty()) { + debug("Removed some annotation targets, adding annotation query"); + state.annotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr + .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), null, EnumSet.copyOf(removedtargets))); + } + + for (final MethodRepr m : diff.methods().added()) { + if (!m.hasValue()) { + debug("Added method with no default value: ", m.name); + debug("Adding class usage to affected usages"); + state.affectedUsages.add(it.createUsage()); + } + } + } + + debug("End of annotation-specific analysis"); + } + + processAddedMethods (state, diff, it); + processRemovedMethods (state, diff, it); + processChangedMethods (state, diff, it); + + if (!processAddedFields (state, diff, it)) { + return false; + } + + if (!processRemovedFields (state, diff, it)) { + return false; + } + + if (!processChangedFields (state, diff, it)) { + return false; + } + } + debug("End of changed classes processing"); + + return true; + } + + private void processRemovedClases(final DiffState state) { + debug("Processing removed classes:"); + for (final ClassRepr c : state.classDiff.removed()) { + myDelta.addDeletedClass(c); + mySelf.appendDependents(c, state.dependants); + debug("Adding usages of class ", c.name); + state.affectedUsages.add(c.createUsage()); + } + debug("End of removed classes processing."); + } + + private void processAddedClasses(final DiffState state) { + debug("Processing added classes:"); + for (final ClassRepr c : state.classDiff.added()) { + debug("Class name: ", c.name); + myDelta.addChangedClass(c.name); + + final TIntHashSet depClasses = myClassToClassDependency.get(c.name); + + if (depClasses != null) { + depClasses.forEach(new TIntProcedure() { + @Override + public boolean execute(int depClass) { + final int fName = myClassToSourceFile.get(depClass); + + if (fName > 0) { + final String f = myContext.getValue(fName); + final File theFile = new File(f); + + if (myFilter.accept(theFile)) { + debug("Adding dependent file ", f); + myAffectedFiles.add(theFile); + } + } + return true; + } + }); + } + } + debug("End of added classes processing."); + } + + private void calaulateAffectedFiles(final DiffState state) { + debug("Checking dependent files:"); + final TIntHashSet dependentFiles = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); + + state.dependants.forEach(new TIntProcedure() { + @Override + public boolean execute(int depClass) { + final int file = myClassToSourceFile.get(depClass); + if (file > 0) { + dependentFiles.add(file); + } + return true; + } + }); + + filewise: + for (final int depFile : dependentFiles.toArray()) { // todo: avoid toArray()? + final File theFile = new File(myContext.getValue(depFile)); + + if (myAffectedFiles.contains(theFile) || myCompiledFiles.contains(theFile)) { + continue filewise; + } + + debug("Dependent file: ", depFile); + final Collection depClusters = mySourceFileToUsages.get(depFile); + if (depClusters != null) { + for (final UsageRepr.Cluster depCluster : depClusters) { + final Set depUsages = depCluster.getUsages(); + if (depUsages == null) { + continue; + } + final Set usages = new HashSet(depUsages); + + usages.retainAll(state.affectedUsages); + + if (!usages.isEmpty()) { + for (UsageRepr.Usage usage : usages) { + final Util.UsageConstraint constraint = state.usageConstraints.get(usage); + + if (constraint == null) { + debug("Added file with no constraints"); + myAffectedFiles.add(theFile); + continue filewise; + } + else { + final TIntHashSet residenceClasses = depCluster.getResidence(usage); + for (final int residentName : residenceClasses.toArray()) { + if (constraint.checkResidence(residentName)) { + debug("Added file with satisfied constraint"); + myAffectedFiles.add(theFile); continue filewise; } } } } } + + if (state.annotationQuery.size() > 0) { + final Collection annotationUsages = mySourceFileToAnnotationUsages.get(depFile); + + for (final UsageRepr.Usage usage : annotationUsages) { + for (final UsageRepr.AnnotationUsage query : state.annotationQuery) { + if (query.satisfies(usage)) { + debug("Added file due to annotation query"); + myAffectedFiles.add(theFile); + continue filewise; + } + } + } + } } } } - - if (removed != null) { - for (final String r : removed) { - affectedFiles.remove(new File(r)); - } - } - - debug("End of Differentiate."); - return works.doWork(affectedFiles); } + + boolean differentiate() { + synchronized (myLock) { + + debug("Begin of Differentiate:"); + + processDisappearedClasses(); + + final List newClasses = new ArrayList(); + myDelta.mySourceFileToClasses.forEachEntry(new TIntObjectProcedure>() { + @Override + public boolean execute(int fileName, Collection classes) { + newClasses.add(new FileClasses(fileName, classes)); + return true; + } + }); + + for (final FileClasses compiledFile : newClasses) { + final int fileName = compiledFile.fileName; + final Set classes = compiledFile.fileClasses; + final Set pastClasses = (Set)mySourceFileToClasses.get(fileName); + final DiffState state = new DiffState(Difference.make(pastClasses, classes)); + + if (!processChangedClasses(state)) { + return false; + } + + processRemovedClases(state); + processAddedClasses(state); + + calaulateAffectedFiles(state); + } + + if (myRemoved != null) { + for (final String r : myRemoved) { + myAffectedFiles.remove(new File(r)); + } + } + + debug("End of Differentiate."); + return myDelayedWorks.doWork(myAffectedFiles); + } + } + } + + public boolean differentiate + (final Mappings delta, + final Collection removed, + final Collection filesToCompile, + final Collection compiledFiles, + final Collection affectedFiles, + final DependentFilesFilter filter, + @Nullable final Callbacks.ConstantAffectionResolver constantSearch) { + return new Differential(delta, removed, filesToCompile, compiledFiles, affectedFiles, filter, constantSearch).differentiate(); } private void cleanupBackDependency(final int className, @Nullable Collection clusters, IntIntMultiMaplet buffer) { diff --git a/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy b/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy index d40e9cc91e9b..92521fb12f09 100644 --- a/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy +++ b/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy @@ -334,15 +334,17 @@ public class IdeaProjectLoader { def componentTag = getComponent(root, "Encoding"); if (componentTag == null) return; componentTag.file?.each {Node fileNode -> - def url = fileNode."@url"; - def charset = fileNode."@charset"; + String url = fileNode."@url"; + String charset = fileNode."@charset"; - if ("PROJECT".equals(url)) { - project.projectCharset = charset; - } - else { - def path = projectMacroExpander.expandMacros(IdeaProjectLoadingUtil.pathFromUrl(url)); - project.filePathToCharset[path] = charset; + if (!StringUtil.isEmptyOrSpaces(charset)) { + if ("PROJECT".equals(url)) { + project.projectCharset = charset; + } + else { + def path = projectMacroExpander.expandMacros(IdeaProjectLoadingUtil.pathFromUrl(url)); + project.filePathToCharset[FileUtil.toCanonicalPath(path)] = charset; + } } } } @@ -632,6 +634,12 @@ public class IdeaProjectLoader { case "JDK_1_5": return "1.5" case "JDK_1_6": return "1.6" case "JDK_1_7": return "1.7" + case "JDK_1_8": return "1.8" + } + + final String prefix = "JDK_"; + if (imlPropertyText != null && imlPropertyText.startsWith(prefix)) { + return imlPropertyText.substring(prefix.length()).replace('_', '.'); } return "1.6" diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java index 5290bf1e5ee3..2df59cd5fa37 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.psi.codeStyle.NameUtil; import org.jetbrains.annotations.NotNull; @@ -38,7 +39,7 @@ public class PrefixMatchingWeigher extends CompletionWeigher { final NameUtil.MatchingCaseSensitivity sensitivity = setting == CodeInsightSettings.NONE ? NameUtil.MatchingCaseSensitivity.NONE : setting == CodeInsightSettings.FIRST_LETTER ? NameUtil.MatchingCaseSensitivity.FIRST_LETTER : NameUtil.MatchingCaseSensitivity.ALL; - final NameUtil.MinusculeMatcher matcher = new NameUtil.MinusculeMatcher(CamelHumpMatcher.applyMiddleMatching(prefix), sensitivity); + final MinusculeMatcher matcher = new MinusculeMatcher(CamelHumpMatcher.applyMiddleMatching(prefix), sensitivity); int max = Integer.MIN_VALUE; for (String lookupString : item.getAllLookupStrings()) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionActionWrapper.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionActionWrapper.java index 685db4510e68..37a1d3b89ef1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionActionWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionActionWrapper.java @@ -32,6 +32,7 @@ public class IntentionActionWrapper implements IntentionAction { private IntentionAction myDelegate; private final String[] myCategories; private final IntentionActionBean myExtension; + private String myFullFamilyName; public IntentionActionWrapper(final IntentionActionBean extension, String[] categories) { myExtension = extension; @@ -60,13 +61,13 @@ public class IntentionActionWrapper implements IntentionAction { return getDelegate().startInWriteAction(); } + @NotNull public String getFullFamilyName(){ - if (myCategories != null) { - return StringUtil.join(myCategories, "/") + "/" + getFamilyName(); - } - else { - return getFamilyName(); + String result = myFullFamilyName; + if (result == null) { + myFullFamilyName = result = myCategories != null ? StringUtil.join(myCategories, "/") + "/" + getFamilyName() : getFamilyName(); } + return result; } public synchronized IntentionAction getDelegate() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index 0a5e258a0c14..3e9b529ad131 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -24,6 +24,7 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.*; import com.intellij.ui.speedSearch.SpeedSearchUtil; @@ -255,7 +256,7 @@ public class LookupCellRenderer implements ListCellRenderer { final String prefix = myLookup.itemPattern(item); if (prefix.length() > 0) { - Iterable ranges = new NameUtil.MinusculeMatcher("*" + prefix, NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(name); + Iterable ranges = new MinusculeMatcher("*" + prefix, NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(name); if (ranges != null) { SimpleTextAttributes highlighted = new SimpleTextAttributes(style, selected ? SELECTED_PREFIX_FOREGROUND_COLOR : PREFIX_FOREGROUND_COLOR); diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 393fd5000bd5..c3839457750b 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -46,6 +46,7 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.psi.PsiElement; +import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.statistics.StatisticsInfo; import com.intellij.psi.statistics.StatisticsManager; @@ -1020,7 +1021,8 @@ public abstract class ChooseByNameBase { String text = EXTRA_ELEM.equals(modelElement) ? null : myModel.getFullName(modelElement); if (text != null) { String shortName = myModel.getElementName(modelElement); - int match = shortName != null && matcher instanceof NameUtil.MinusculeMatcher ? ((NameUtil.MinusculeMatcher)matcher).matchingDegree(shortName) : Integer.MIN_VALUE; + int match = shortName != null && matcher instanceof MinusculeMatcher + ? ((MinusculeMatcher)matcher).matchingDegree(shortName) : Integer.MIN_VALUE; int stats = StatisticsManager.getInstance().getUseCount(new StatisticsInfo(statContext, text)); if (stats > best || stats == best && match > bestMatch) { best = stats; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java index 89bb47436d43..7fbc2a2fdbd4 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; +import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.util.proximity.PsiProximityComparator; import com.intellij.util.Function; @@ -147,10 +148,10 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider if (name == null) return false; final List suspects = split(name, base); - final List> patternsAndMatchers = - ContainerUtil.map2List(split(qualifierPattern, base), new Function>() { + final List> patternsAndMatchers = + ContainerUtil.map2List(split(qualifierPattern, base), new Function>() { @Override - public Pair fun(String s) { + public Pair fun(String s) { return Pair.create(getNamePattern(base, s), buildPatternMatcher(getNamePattern(base, s))); } }); @@ -159,9 +160,9 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider try { patterns: - for (Pair patternAndMatcher : patternsAndMatchers) { + for (Pair patternAndMatcher : patternsAndMatchers) { final String pattern = patternAndMatcher.first; - final NameUtil.MinusculeMatcher matcher = patternAndMatcher.second; + final MinusculeMatcher matcher = patternAndMatcher.second; if (!pattern.isEmpty()) { for (int j = matchPosition; j < suspects.size() - 1; j++) { String suspect = suspects.get(j); @@ -204,7 +205,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider pattern = pattern.substring(1); } - final NameUtil.MinusculeMatcher matcher = buildPatternMatcher(pattern); + final MinusculeMatcher matcher = buildPatternMatcher(pattern); try { for (String name : names) { @@ -221,7 +222,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider } } - private static boolean matches(ChooseByNameBase base, String pattern, NameUtil.MinusculeMatcher matcher, String name) { + private static boolean matches(ChooseByNameBase base, String pattern, MinusculeMatcher matcher, String name) { boolean matches = false; if (name != null) { if (base.getModel() instanceof CustomMatcherModel) { @@ -236,7 +237,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider return matches; } - private static NameUtil.MinusculeMatcher buildPatternMatcher(String pattern) { + private static MinusculeMatcher buildPatternMatcher(String pattern) { return NameUtil.buildMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE); } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/markup/AttributesFlyweight.java b/platform/platform-api/src/com/intellij/openapi/editor/markup/AttributesFlyweight.java index b6ea12c0257f..05fa2cd09b82 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/markup/AttributesFlyweight.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/markup/AttributesFlyweight.java @@ -29,7 +29,55 @@ import java.awt.*; public class AttributesFlyweight { private final int myHashCode; - private static final StripedLockConcurrentHashMap entries = new StripedLockConcurrentHashMap(); + private static final StripedLockConcurrentHashMap entries = new StripedLockConcurrentHashMap(); + private static final ThreadLocal ourKey = new ThreadLocal(); + + private static class FlyweightKey implements Cloneable { + Color foreground; + Color background; + @JdkConstants.FontStyle int fontType; + Color effectColor; + EffectType effectType; + Color errorStripeColor; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof FlyweightKey)) return false; + + FlyweightKey key = (FlyweightKey)o; + + if (fontType != key.fontType) return false; + if (background != null ? !background.equals(key.background) : key.background != null) return false; + if (effectColor != null ? !effectColor.equals(key.effectColor) : key.effectColor != null) return false; + if (effectType != key.effectType) return false; + if (errorStripeColor != null ? !errorStripeColor.equals(key.errorStripeColor) : key.errorStripeColor != null) return false; + if (foreground != null ? !foreground.equals(key.foreground) : key.foreground != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = foreground != null ? foreground.hashCode() : 0; + result = 31 * result + (background != null ? background.hashCode() : 0); + result = 31 * result + fontType; + result = 31 * result + (effectColor != null ? effectColor.hashCode() : 0); + result = 31 * result + (effectType != null ? effectType.hashCode() : 0); + result = 31 * result + (errorStripeColor != null ? errorStripeColor.hashCode() : 0); + return result; + } + + @Override + protected FlyweightKey clone() { + try { + return (FlyweightKey)super.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + } @NotNull public static AttributesFlyweight create(Color foreground, @@ -38,8 +86,23 @@ public class AttributesFlyweight { Color effectColor, EffectType effectType, Color errorStripeColor) { - AttributesFlyweight key = new AttributesFlyweight(foreground, background, fontType, effectColor, effectType, errorStripeColor); - return ConcurrencyUtil.cacheOrGet(entries, key, key); + FlyweightKey key = ourKey.get(); + if (key == null) { + ourKey.set(key = new FlyweightKey()); + } + key.foreground = foreground; + key.background = background; + key.fontType = fontType; + key.effectColor = effectColor; + key.effectType = effectType; + key.errorStripeColor = errorStripeColor; + + AttributesFlyweight flyweight = entries.get(key); + if (flyweight != null) { + return flyweight; + } + + return ConcurrencyUtil.cacheOrGet(entries, key.clone(), new AttributesFlyweight(foreground, background, fontType, effectColor, effectType, errorStripeColor)); } private final Color myForeground; diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java index 367957385950..839eea53bd76 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java @@ -716,7 +716,7 @@ public class Messages { } /** - * Shows dialog with given message and title, infomation icon {@link #getInformationIcon()} and OK button + * Shows dialog with given message and title, information icon {@link #getInformationIcon()} and OK button */ public static void showInfoMessage(Component component, String message, String title) { if (canShowMacSheetPanel()) { @@ -728,7 +728,7 @@ public class Messages { } /** - * Shows dialog with given message and title, infomation icon {@link #getInformationIcon()} and OK button + * Shows dialog with given message and title, information icon {@link #getInformationIcon()} and OK button */ public static void showInfoMessage(Project project, @Nls String message, @Nls String title) { if (canShowMacSheetPanel()) { @@ -740,7 +740,7 @@ public class Messages { } /** - * Shows dialog with given message and title, infomation icon {@link #getInformationIcon()} and OK button + * Shows dialog with given message and title, information icon {@link #getInformationIcon()} and OK button */ public static void showInfoMessage(String message, String title) { if (canShowMacSheetPanel()) { diff --git a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java index b75cd5db6fa3..8e3f0f5ba13e 100644 --- a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java +++ b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java @@ -18,7 +18,7 @@ package com.intellij.ui.speedSearch; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; -import com.intellij.psi.codeStyle.NameUtil; +import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Processor; @@ -65,12 +65,12 @@ public final class SpeedSearchUtil { final Matcher matcher, final Color selectedBg, final boolean selected) { - if (!(matcher instanceof NameUtil.MinusculeMatcher) || (Registry.is("ide.highlight.match.in.selected.only") && !selected)) { + if (!(matcher instanceof MinusculeMatcher) || (Registry.is("ide.highlight.match.in.selected.only") && !selected)) { component.append(text, attributes); return; } - final Iterable iterable = ((NameUtil.MinusculeMatcher)matcher).matchingFragments(text); + final Iterable iterable = ((MinusculeMatcher)matcher).matchingFragments(text); if (iterable != null) { final Color fg = attributes.getFgColor(); final int style = attributes.getStyle(); diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java index 9d6da6f8d442..00ef9f89ad09 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java @@ -93,6 +93,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private final DefaultActionGroup mySecondaryActions = new DefaultActionGroup(); private boolean myMinimalMode; + private boolean myForceUseMacEnhancements; public ActionButton getSecondaryActionsButton() { return mySecondaryActionsButton; @@ -164,7 +165,11 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } private boolean doMacEnhancementsForMainToolbar() { - return (UIUtil.isUnderAquaLookAndFeel() && ActionPlaces.MAIN_TOOLBAR.equals(myPlace)); + return (UIUtil.isUnderAquaLookAndFeel() && (ActionPlaces.MAIN_TOOLBAR.equals(myPlace) || myForceUseMacEnhancements)); + } + + public void setForceUseMacEnhancements(boolean useMacEnhancements) { + myForceUseMacEnhancements = useMacEnhancements; } private boolean isInsideNavBar() { diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchComparator.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchComparator.java index 0f3b5dccdb64..31e2f6597412 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchComparator.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchComparator.java @@ -17,6 +17,7 @@ package com.intellij.ui; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.psi.codeStyle.NameUtil; import org.jetbrains.annotations.Nullable; @@ -24,7 +25,7 @@ import org.jetbrains.annotations.Nullable; * @author Konstantin Bulenkov */ public class SpeedSearchComparator { - private NameUtil.MinusculeMatcher myMinusculeMatcher; + private MinusculeMatcher myMinusculeMatcher; private String myRecentSearchText; private boolean myShouldMatchFromTheBeginning; private boolean myShouldMatchCamelCase; @@ -52,7 +53,7 @@ public class SpeedSearchComparator { if (!myShouldMatchFromTheBeginning && !pattern.startsWith("*")) { pattern = "*" + pattern; } - myMinusculeMatcher = new NameUtil.MinusculeMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE); + myMinusculeMatcher = new MinusculeMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE); } return myMinusculeMatcher.matchingFragments(text); } diff --git a/platform/platform-tests/testSrc/com/intellij/history/integration/FileListeningTest.java b/platform/platform-tests/testSrc/com/intellij/history/integration/FileListeningTest.java index f5cbf86aac8a..2d65ec17ac8f 100644 --- a/platform/platform-tests/testSrc/com/intellij/history/integration/FileListeningTest.java +++ b/platform/platform-tests/testSrc/com/intellij/history/integration/FileListeningTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,7 +72,7 @@ public class FileListeningTest extends IntegrationTestCase { LocalFileSystem.getInstance().refresh(false); List changes = getVcs().getChangeListInTests().getChangesInTests().get(0).getChanges(); - assertEquals(4, changes.size()); + assertEquals(changes.toString(), 4, changes.size()); List actual = new SmartList(); for (Change each : changes) { actual.add(((StructuralChange)each).getPath()); @@ -100,7 +100,7 @@ public class FileListeningTest extends IntegrationTestCase { VirtualFile f = createFile("file.txt"); assertEquals(2, getRevisionsFor(f).size()); - f.rename(null, "file2.txt"); + f.rename(this, "file2.txt"); assertEquals(3, getRevisionsFor(f).size()); } @@ -125,7 +125,7 @@ public class FileListeningTest extends IntegrationTestCase { addFileListenerDuring(l, new RunnableAdapter() { @Override public void doRun() throws IOException { - f.rename(null, "new.txt"); + f.rename(this, "new.txt"); } }); @@ -139,7 +139,7 @@ public class FileListeningTest extends IntegrationTestCase { VirtualFile f = createFile("file.hprof"); assertEquals(before, getRevisionsFor(myRoot).size()); - f.rename(null, "file.txt"); + f.rename(this, "file.txt"); assertEquals(before + 1, getRevisionsFor(myRoot).size()); assertEquals(2, getRevisionsFor(f).size()); @@ -151,7 +151,7 @@ public class FileListeningTest extends IntegrationTestCase { VirtualFile f = createFile("file.txt"); assertEquals(before + 1, getRevisionsFor(myRoot).size()); - f.rename(null, "file.hprof"); + f.rename(this, "file.hprof"); assertEquals(before + 2, getRevisionsFor(myRoot).size()); } @@ -161,7 +161,7 @@ public class FileListeningTest extends IntegrationTestCase { VirtualFile f = createFile(FILTERED_DIR_NAME); assertEquals(before, getRevisionsFor(myRoot).size()); - f.rename(null, "not_filtered"); + f.rename(this, "not_filtered"); assertEquals(before + 1, getRevisionsFor(myRoot).size()); assertEquals(2, getRevisionsFor(f).size()); @@ -173,7 +173,7 @@ public class FileListeningTest extends IntegrationTestCase { VirtualFile f = createDirectory("not_filtered"); assertEquals(before + 1, getRevisionsFor(myRoot).size()); - f.rename(null, FILTERED_DIR_NAME); + f.rename(this, FILTERED_DIR_NAME); assertEquals(before + 2, getRevisionsFor(myRoot).size()); } @@ -188,7 +188,7 @@ public class FileListeningTest extends IntegrationTestCase { assertEquals(4, getRevisionsFor(f).size()); } - public void testIgnoringROStstusChangeForUnversionedFiles() throws Exception { + public void testIgnoringROStatusChangeForUnversionedFiles() throws Exception { int before = getRevisionsFor(myRoot).size(); VirtualFile f = createFile("f.hprof"); @@ -202,7 +202,7 @@ public class FileListeningTest extends IntegrationTestCase { int before = getRevisionsFor(myRoot).size(); - f.delete(null); + f.delete(this); assertEquals(before + 1, getRevisionsFor(myRoot).size()); } @@ -210,24 +210,26 @@ public class FileListeningTest extends IntegrationTestCase { int before = getRevisionsFor(myRoot).size(); VirtualFile f = createDirectory(FILTERED_DIR_NAME); - f.delete(null); + f.delete(this); assertEquals(before, getRevisionsFor(myRoot).size()); } public void testDeletionDoesNotVersionIgnoredFilesRecursively() throws Exception { String dir1 = createDirectoryExternally("dir"); - String f1 = createFileExternally("dir/f.txt"); + createFileExternally("dir/f.txt"); createFileExternally("dir/f.class"); createFileExternally("dir/subdir/f.txt"); - String dir2 = createDirectoryExternally("dir/subdir/subdir2"); - String f2 = createFileExternally("dir/subdir/subdir2/f.txt"); + createDirectoryExternally("dir/subdir/subdir2"); + createFileExternally("dir/subdir/subdir2/f.txt"); LocalFileSystem.getInstance().refresh(false); addExcludedDir(myRoot.getPath() + "/dir/subdir"); addContentRoot(myRoot.getPath() + "/dir/subdir/subdir2"); - LocalFileSystem.getInstance().findFileByPath(dir1).delete(this); + final VirtualFile vDir1 = LocalFileSystem.getInstance().findFileByPath(dir1); + assertNotNull(dir1, vDir1); + vDir1.delete(this); List changes = getVcs().getChangeListInTests().getChangesInTests().get(0).getChanges(); assertEquals(1, changes.size()); diff --git a/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java b/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java index 72ac2b2fccac..c2a329e9dcae 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java @@ -20,6 +20,7 @@ package com.intellij.psi.util; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.codeStyle.MinusculeMatcher; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.UsefulTestCase; @@ -312,57 +313,57 @@ public class NameUtilTest extends UsefulTestCase { } public void testMinusculeFirstLetter() { - assertTrue(new NameUtil.MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic")); - assertFalse(new NameUtil.MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic")); - assertTrue(new NameUtil.MinusculeMatcher("cL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("class")); - assertTrue(new NameUtil.MinusculeMatcher("CL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("Class")); - assertFalse(new NameUtil.MinusculeMatcher("abc", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("_abc")); + assertTrue(new MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic")); + assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic")); + assertTrue(new MinusculeMatcher("cL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("class")); + assertTrue(new MinusculeMatcher("CL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("Class")); + assertFalse(new MinusculeMatcher("abc", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("_abc")); } public void testMinusculeAllImportant() { - assertTrue(new NameUtil.MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); - assertFalse(new NameUtil.MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic")); - assertFalse(new NameUtil.MinusculeMatcher("FOO", NameUtil.MatchingCaseSensitivity.ALL).matches("foo")); - assertFalse(new NameUtil.MinusculeMatcher("foo", NameUtil.MatchingCaseSensitivity.ALL).matches("fOO")); - assertFalse(new NameUtil.MinusculeMatcher("Wl", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); - assertTrue(new NameUtil.MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); - assertFalse(new NameUtil.MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("Weblogic")); - assertFalse(new NameUtil.MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic")); - assertFalse(new NameUtil.MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); - assertFalse(new NameUtil.MinusculeMatcher("Str", NameUtil.MatchingCaseSensitivity.ALL).matches("SomeThingRidiculous")); + assertTrue(new MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); + assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic")); + assertFalse(new MinusculeMatcher("FOO", NameUtil.MatchingCaseSensitivity.ALL).matches("foo")); + assertFalse(new MinusculeMatcher("foo", NameUtil.MatchingCaseSensitivity.ALL).matches("fOO")); + assertFalse(new MinusculeMatcher("Wl", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); + assertTrue(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); + assertFalse(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("Weblogic")); + assertFalse(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic")); + assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic")); + assertFalse(new MinusculeMatcher("Str", NameUtil.MatchingCaseSensitivity.ALL).matches("SomeThingRidiculous")); } public void testMatchingFragments() { @NonNls String sample = "NoClassDefFoundException"; // 0 2 7 10 15 21 - assertOrderedEquals(new NameUtil.MinusculeMatcher("ncldfou*ion", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), + assertOrderedEquals(new MinusculeMatcher("ncldfou*ion", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), TextRange.from(0, 1), TextRange.from(2, 2), TextRange.from(7, 1), TextRange.from(10, 3), TextRange.from(21, 3)); sample = "doGet(HttpServletRequest, HttpServletResponse):void"; // 0 22 - assertOrderedEquals(new NameUtil.MinusculeMatcher("d*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), + assertOrderedEquals(new MinusculeMatcher("d*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), TextRange.from(0, 1), TextRange.from(22, 2)); - assertOrderedEquals(new NameUtil.MinusculeMatcher("doge*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), + assertOrderedEquals(new MinusculeMatcher("doge*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), TextRange.from(0, 4), TextRange.from(22, 2)); sample = "_test"; - assertOrderedEquals(new NameUtil.MinusculeMatcher("_", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), + assertOrderedEquals(new MinusculeMatcher("_", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), TextRange.from(0, 1)); - assertOrderedEquals(new NameUtil.MinusculeMatcher("_t", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), + assertOrderedEquals(new MinusculeMatcher("_t", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), TextRange.from(0, 2)); } public void testMatchingFragmentsSorted() { @NonNls String sample = "SWUPGRADEHDLRFSPR7TEST"; // 0 9 12 - assertOrderedEquals(new NameUtil.MinusculeMatcher("SWU*H*R", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), + assertOrderedEquals(new MinusculeMatcher("SWU*H*R", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), TextRange.from(0, 3), TextRange.from(9, 1), TextRange.from(12, 1)); } public void testPreferCapsMatching() { String sample = "getCurrentUser"; // 0 4 10 - assertOrderedEquals(new NameUtil.MinusculeMatcher("getCU", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), + assertOrderedEquals(new MinusculeMatcher("getCU", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample), TextRange.from(0, 4), TextRange.from(10, 1)); } @@ -390,7 +391,7 @@ public class NameUtilTest extends UsefulTestCase { } public void testMeaningfulMatchingDegree() { - assertTrue(new NameUtil.MinusculeMatcher(" EUC-", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matchingDegree("x-EUC-TW") > Integer.MIN_VALUE); + assertTrue(new MinusculeMatcher(" EUC-", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matchingDegree("x-EUC-TW") > Integer.MIN_VALUE); } private static void assertPreference(@NonNls String pattern, @@ -403,7 +404,7 @@ public class NameUtilTest extends UsefulTestCase { @NonNls String less, @NonNls String more, NameUtil.MatchingCaseSensitivity sensitivity) { - NameUtil.MinusculeMatcher matcher = new NameUtil.MinusculeMatcher(pattern, sensitivity); + MinusculeMatcher matcher = new MinusculeMatcher(pattern, sensitivity); int iLess = matcher.matchingDegree(less); int iMore = matcher.matchingDegree(more); assertTrue(iLess + ">=" + iMore + "; " + less + ">=" + more, iLess < iMore); @@ -411,24 +412,24 @@ public class NameUtilTest extends UsefulTestCase { public void testPerformance() { @NonNls final String longName = "ThisIsAQuiteLongNameWithParentheses().Dots.-Minuses-_UNDERSCORES_digits239:colons:/slashes\\AndOfCourseManyLetters"; - final List matching = new ArrayList(); - final List nonMatching = new ArrayList(); + final List matching = new ArrayList(); + final List nonMatching = new ArrayList(); for (String s : CollectionFactory.ar("*", "*i", "*a", "*u", "T", "ti", longName, longName.substring(0, 20))) { - matching.add(new NameUtil.MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE)); + matching.add(new MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE)); } for (String s : CollectionFactory.ar("A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ta")) { - nonMatching.add(new NameUtil.MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE)); + nonMatching.add(new MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE)); } - PlatformTestUtil.startPerformanceTest("Matcher is slow", 1200, new ThrowableRunnable() { + PlatformTestUtil.startPerformanceTest("Matcher is slow", 1700, new ThrowableRunnable() { @Override public void run() { for (int i = 0; i < 100000; i++) { - for (NameUtil.MinusculeMatcher matcher : matching) { + for (MinusculeMatcher matcher : matching) { assertTrue(matcher.matches(longName)); } - for (NameUtil.MinusculeMatcher matcher : nonMatching) { + for (MinusculeMatcher matcher : nonMatching) { assertFalse(matcher.matches(longName)); } } diff --git a/platform/testFramework/src/com/intellij/testFramework/HighlightTestInfo.java b/platform/testFramework/src/com/intellij/testFramework/HighlightTestInfo.java index 9d12ebc4f484..407ae199627e 100644 --- a/platform/testFramework/src/com/intellij/testFramework/HighlightTestInfo.java +++ b/platform/testFramework/src/com/intellij/testFramework/HighlightTestInfo.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. @@ -36,6 +36,7 @@ public abstract class HighlightTestInfo implements Disposable { Disposer.register(parentDisposable, this); myPlace = parentDisposable.toString(); } + public HighlightTestInfo checkWarnings() { checkWarnings = true; return this; } public HighlightTestInfo checkWeakWarnings() { checkWeakWarnings = true; return this; } public HighlightTestInfo checkInfos() { checkInfos = true; return this; } @@ -43,10 +44,14 @@ public abstract class HighlightTestInfo implements Disposable { public HighlightTestInfo projectRoot(@NonNls @NotNull String root) { projectRoot = root; return this; } public HighlightTestInfo test() throws Exception { - doTest(); - tested = true; - Disposer.dispose(this); - return this; + try { + doTest(); + return this; + } + finally { + tested = true; + Disposer.dispose(this); + } } @Override diff --git a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java new file mode 100644 index 000000000000..32074ac649f6 --- /dev/null +++ b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java @@ -0,0 +1,296 @@ +/* + * 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.psi.codeStyle; + +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.FList; +import com.intellij.util.text.CharArrayCharSequence; +import com.intellij.util.text.Matcher; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; + +/** +* @author peter +*/ +public class MinusculeMatcher implements Matcher { + private final char[] myPattern; + private final NameUtil.MatchingCaseSensitivity myOptions; + + public MinusculeMatcher(String pattern, NameUtil.MatchingCaseSensitivity options) { + myOptions = options; + myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").toCharArray(); + } + + @Nullable + private FList matchName(String name, int patternIndex, int nameIndex) { + if (patternIndex == myPattern.length) { + return FList.emptyList(); + } + if ('*' == myPattern[patternIndex]) { + return skipChars(name, patternIndex, nameIndex, true); + } + if (nameIndex == name.length()) { + return null; + } + + if ('.' == myPattern[patternIndex] && name.charAt(nameIndex) != '.') { + return skipChars(name, patternIndex, nameIndex, false); + } + + if (' ' == myPattern[patternIndex] && patternIndex != myPattern.length - 1) { + return skipWords(name, patternIndex, nameIndex); + } + + if ((patternIndex == 0 || patternIndex == 1 && myPattern[0] == ' ' && nameIndex == 0) && + myOptions != NameUtil.MatchingCaseSensitivity.NONE && name.charAt(nameIndex) != myPattern[patternIndex]) { + return null; + } + + if (NameUtil.isWordSeparator(name.charAt(nameIndex))) { + return skipSeparators(name, patternIndex, nameIndex); + } + + if (StringUtil.toLowerCase(name.charAt(nameIndex)) != StringUtil.toLowerCase(myPattern[patternIndex])) { + if (Character.isDigit(name.charAt(nameIndex)) && nameIndex > 0 || (name.charAt(nameIndex) == '.' && name.indexOf('.', nameIndex + 1) > 0)) { + return matchName(name, patternIndex, nameIndex + 1); + } + return null; + } + + if (myOptions == NameUtil.MatchingCaseSensitivity.ALL && name.charAt(nameIndex) != myPattern[patternIndex]) { + return null; + } + + int nextStart = NameUtil.nextWord(name, nameIndex); + + int lastUpper = NameUtil.isWordStart(myPattern[patternIndex]) ? 0 : -1; + + int i = 1; + while (true) { + if (patternIndex + i == myPattern.length || i + nameIndex == nextStart) { + break; + } + char p = myPattern[patternIndex + i]; + char w = name.charAt(i + nameIndex); + if (lastUpper == i - 1 && NameUtil.isWordStart(p) && myOptions != NameUtil.MatchingCaseSensitivity.ALL) { + if (p == w) { + lastUpper = i; + } + p = StringUtil.toLowerCase(p); + } + + if (myOptions != NameUtil.MatchingCaseSensitivity.ALL) { + w = StringUtil.toLowerCase(w); + } + if (w != p) { + break; + } + i++; + } + + if (isFinalSpaceMatch(name, patternIndex, nameIndex, nextStart, i)) { + return FList.emptyList().prepend(TextRange.from(nameIndex, i)); + } + + return matchAfterFragment(name, patternIndex, nameIndex, nextStart, lastUpper, i); + } + + private boolean isFinalSpaceMatch(String name, int patternIndex, int nameIndex, int nextStart, int i) { + return nextStart == name.length() && + patternIndex + i == myPattern.length - 1 && + ' ' == myPattern[patternIndex + i] && + (i == 1 && NameUtil.isWordStart(myPattern[patternIndex]) || i + nameIndex == name.length()); + } + + @Nullable + private FList matchAfterFragment(String name, int patternIndex, int nameIndex, int nextStart, int lastUpper, int matchLen) { + boolean star = patternIndex + matchLen < myPattern.length && myPattern[patternIndex + matchLen] == '*'; + if (lastUpper >= 0) { + FList ranges = matchName(name, patternIndex + lastUpper + 1, star && matchLen == lastUpper ? nameIndex + lastUpper : nextStart); + if (ranges != null) { + return prependRange(ranges, nameIndex, lastUpper + 1); + } + } + + int trial = matchLen; + while (trial > 0) { + FList ranges = matchName(name, patternIndex + trial, nextStart); + if (ranges != null) { + return prependRange(ranges, nameIndex, trial); + } + trial--; + } + + FList ranges = matchName(name, patternIndex + matchLen, nameIndex + matchLen); + if (ranges != null) { + return prependRange(ranges, nameIndex, matchLen); + } + return null; + } + + private static FList prependRange(FList ranges, int from, int length) { + TextRange head = ranges.getHead(); + if (head != null && head.getStartOffset() == from + length) { + return ranges.getTail().prepend(new TextRange(from, head.getEndOffset())); + } + return ranges.prepend(TextRange.from(from, length)); + } + + @Nullable + private FList skipSeparators(String name, int patternIndex, int nameIndex) { + int nextStart = NameUtil.nextWord(name, nameIndex); + assert nextStart - nameIndex == 1 : "'" + name + "'" + nameIndex + " " + nextStart; + char p = myPattern[patternIndex]; + if (NameUtil.isWordSeparator(p)) { + if (myOptions != NameUtil.MatchingCaseSensitivity.NONE && + nameIndex == 0 && name.length() > 1 && patternIndex + 1 < myPattern.length && + NameUtil.isWordSeparator(name.charAt(1)) && !NameUtil.isWordSeparator(myPattern[patternIndex + 1])) { + return null; + } + + final FList ranges = matchName(name, patternIndex + 1, nextStart); + if (ranges != null) { + return prependRange(ranges, nameIndex, 1); + } + + return null; + } + + return matchName(name, patternIndex, nextStart); + } + + @Nullable + private FList skipChars(String name, int patternIndex, int nameIndex, boolean maySkipNextChar) { + while ('*' == myPattern[patternIndex]) { + patternIndex++; + if (patternIndex == myPattern.length) { + return FList.emptyList(); + } + } + + String nextChar = String.valueOf(myPattern[patternIndex]); + boolean upper = Character.isUpperCase(myPattern[patternIndex]); + + int fromIndex = nameIndex; + while (true) { + int next = StringUtil.indexOfIgnoreCase(name, nextChar, fromIndex); + if (next < 0) { + break; + } + if (upper && next > 0 && !Character.isUpperCase(name.charAt(next))) { + fromIndex = next + 1; + continue; + } + + FList ranges = matchName(name, patternIndex, next); + if (ranges != null) { + return ranges; + } + if (!maySkipNextChar) { + return null; + } + fromIndex = next + 1; + } + return null; + } + + @Nullable + private FList skipWords(String name, int patternIndex, int nameIndex) { + while (' ' == myPattern[patternIndex]) { + patternIndex++; + if (patternIndex == myPattern.length) { + return null; + } + } + + if (nameIndex == 0 || NameUtil.isWordStart(name, nameIndex)) { + FList ranges = matchName(name, patternIndex, nameIndex); + if (ranges != null) { + return ranges; + } + } + + boolean separatorInPattern = NameUtil.isWordSeparator(myPattern[patternIndex]); + int fromIndex = nameIndex; + while (fromIndex < name.length()) { + int next = separatorInPattern ? name.indexOf(myPattern[patternIndex], fromIndex) : NameUtil.nextWord(name, fromIndex); + if (next < 0) { + break; + } + + FList ranges = matchName(name, patternIndex, next); + if (ranges != null) { + return ranges; + } + fromIndex = next; + if (separatorInPattern) { + fromIndex++; + } + } + return null; + } + + public int matchingDegree(String name) { + Iterable iterable = matchingFragments(name); + if (iterable == null) return Integer.MIN_VALUE; + + int fragmentCount = 0; + int matchingCase = 0; + CharArrayCharSequence seq = new CharArrayCharSequence(myPattern); + int p = -1; + TextRange first = null; + for (TextRange range : iterable) { + if (first == null) { + first = range; + } + for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) { + char c = name.charAt(i); + p = StringUtil.indexOf(seq, c, p + 1, myPattern.length, false); + if (p < 0) { + break; + } + matchingCase += c == myPattern[p] ? 1 : 0; + } + fragmentCount++; + } + + int commonStart = 0; + while (commonStart < name.length() && commonStart < myPattern.length && name.charAt(commonStart) == myPattern[commonStart]) { + commonStart++; + } + + boolean prefixMatching = first != null && first.getStartOffset() == 0; + boolean middleWordStart = first != null && first.getStartOffset() > 0 && NameUtil.isWordStart(name, first.getStartOffset()); + + return -fragmentCount + matchingCase * 10 + commonStart + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 100; + } + + @Override + public boolean matches(String name) { + return matchingFragments(name) != null; + } + + @Nullable + public Iterable matchingFragments(String name) { + if (name.isEmpty()) { + return myPattern.length == 0 ? Collections.emptyList() : null; + } + + return matchName(name, 0, 0); + } +} diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 1fd815e56922..5725e6460a48 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -15,20 +15,15 @@ */ package com.intellij.psi.codeStyle; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtilRt; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.FList; -import com.intellij.util.text.CharArrayCharSequence; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class NameUtil { @@ -331,24 +326,24 @@ public class NameUtil { return suggestion; } - private static boolean isWordStart(String text, int i) { + static boolean isWordStart(String text, int i) { if (isWordStart(text.charAt(i))) { return true; } if (!Character.isLetterOrDigit(text.charAt(i))) { return false; } - if (i > 0 && (MinusculeMatcher.isWordSeparator(text.charAt(i - 1)) || text.charAt(i - 1) == '.')) { + if (i > 0 && (isWordSeparator(text.charAt(i - 1)) || text.charAt(i - 1) == '.')) { return true; } return false; } - private static boolean isWordStart(char p) { + static boolean isWordStart(char p) { return Character.isUpperCase(p) || Character.isDigit(p); } - private static int nextWord(String text, int start) { + static int nextWord(String text, int start) { if (!Character.isLetterOrDigit(text.charAt(start))) { return start + 1; } @@ -378,6 +373,10 @@ public class NameUtil { } } + static boolean isWordSeparator(char c) { + return Character.isWhitespace(c) || c == '_' || c == '-' || c == ':'; + } + /** * @deprecated use com.intellij.util.text.Matcher */ @@ -409,276 +408,4 @@ public class NameUtil { public enum MatchingCaseSensitivity { NONE, FIRST_LETTER, ALL } - - public static class MinusculeMatcher implements com.intellij.util.text.Matcher { - private final char[] myPattern; - private final MatchingCaseSensitivity myOptions; - - public MinusculeMatcher(String pattern, MatchingCaseSensitivity options) { - myOptions = options; - myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").toCharArray(); - } - - @Nullable - private FList matchName(String name, int patternIndex, int nameIndex) { - if (patternIndex == myPattern.length) { - return FList.emptyList(); - } - if ('*' == myPattern[patternIndex]) { - return skipChars(name, patternIndex, nameIndex, true); - } - if (nameIndex == name.length()) { - return null; - } - - if ('.' == myPattern[patternIndex] && name.charAt(nameIndex) != '.') { - return skipChars(name, patternIndex, nameIndex, false); - } - - if (' ' == myPattern[patternIndex] && patternIndex != myPattern.length - 1) { - return skipWords(name, patternIndex, nameIndex); - } - - if ((patternIndex == 0 || patternIndex == 1 && myPattern[0] == ' ' && nameIndex == 0) && - myOptions != MatchingCaseSensitivity.NONE && name.charAt(nameIndex) != myPattern[patternIndex]) { - return null; - } - - if (isWordSeparator(name.charAt(nameIndex))) { - return skipSeparators(name, patternIndex, nameIndex); - } - - if (StringUtil.toLowerCase(name.charAt(nameIndex)) != StringUtil.toLowerCase(myPattern[patternIndex])) { - if (Character.isDigit(name.charAt(nameIndex)) && nameIndex > 0 || (name.charAt(nameIndex) == '.' && name.indexOf('.', nameIndex + 1) > 0)) { - return matchName(name, patternIndex, nameIndex + 1); - } - return null; - } - - if (myOptions == MatchingCaseSensitivity.ALL && name.charAt(nameIndex) != myPattern[patternIndex]) { - return null; - } - - int nextStart = NameUtil.nextWord(name, nameIndex); - - int lastUpper = isWordStart(myPattern[patternIndex]) ? 0 : -1; - - int i = 1; - while (true) { - if (patternIndex + i == myPattern.length || i + nameIndex == nextStart) { - break; - } - char p = myPattern[patternIndex + i]; - char w = name.charAt(i + nameIndex); - if (lastUpper == i - 1 && isWordStart(p) && myOptions != MatchingCaseSensitivity.ALL) { - if (p == w) { - lastUpper = i; - } - p = StringUtil.toLowerCase(p); - } - - if (myOptions != MatchingCaseSensitivity.ALL) { - w = StringUtil.toLowerCase(w); - } - if (w != p) { - break; - } - i++; - } - - if (isFinalSpaceMatch(name, patternIndex, nameIndex, nextStart, i)) { - return FList.emptyList().prepend(TextRange.from(nameIndex, i)); - } - - return matchAfterFragment(name, patternIndex, nameIndex, nextStart, lastUpper, i); - } - - private boolean isFinalSpaceMatch(String name, int patternIndex, int nameIndex, int nextStart, int i) { - return nextStart == name.length() && - patternIndex + i == myPattern.length - 1 && - ' ' == myPattern[patternIndex + i] && - (i == 1 && isWordStart(myPattern[patternIndex]) || i + nameIndex == name.length()); - } - - @Nullable - private FList matchAfterFragment(String name, int patternIndex, int nameIndex, int nextStart, int lastUpper, int matchLen) { - boolean star = patternIndex + matchLen < myPattern.length && myPattern[patternIndex + matchLen] == '*'; - if (lastUpper >= 0) { - FList ranges = matchName(name, patternIndex + lastUpper + 1, star && matchLen == lastUpper ? nameIndex + lastUpper : nextStart); - if (ranges != null) { - return prependRange(ranges, nameIndex, lastUpper + 1); - } - } - - int trial = matchLen; - while (trial > 0) { - FList ranges = matchName(name, patternIndex + trial, nextStart); - if (ranges != null) { - return prependRange(ranges, nameIndex, trial); - } - trial--; - } - - FList ranges = matchName(name, patternIndex + matchLen, nameIndex + matchLen); - if (ranges != null) { - return prependRange(ranges, nameIndex, matchLen); - } - return null; - } - - private static FList prependRange(FList ranges, int from, int length) { - TextRange head = ranges.getHead(); - if (head != null && head.getStartOffset() == from + length) { - return ranges.getTail().prepend(new TextRange(from, head.getEndOffset())); - } - return ranges.prepend(TextRange.from(from, length)); - } - - private static boolean isWordSeparator(char c) { - return Character.isWhitespace(c) || c == '_' || c == '-' || c == ':'; - } - - @Nullable - private FList skipSeparators(String name, int patternIndex, int nameIndex) { - int nextStart = NameUtil.nextWord(name, nameIndex); - assert nextStart - nameIndex == 1 : "'" + name + "'" + nameIndex + " " + nextStart; - char p = myPattern[patternIndex]; - if (isWordSeparator(p)) { - if (myOptions != MatchingCaseSensitivity.NONE && - nameIndex == 0 && name.length() > 1 && patternIndex + 1 < myPattern.length && - isWordSeparator(name.charAt(1)) && !isWordSeparator(myPattern[patternIndex + 1])) { - return null; - } - - final FList ranges = matchName(name, patternIndex + 1, nextStart); - if (ranges != null) { - return prependRange(ranges, nameIndex, 1); - } - - return null; - } - - return matchName(name, patternIndex, nextStart); - } - - @Nullable - private FList skipChars(String name, int patternIndex, int nameIndex, boolean maySkipNextChar) { - while ('*' == myPattern[patternIndex]) { - patternIndex++; - if (patternIndex == myPattern.length) { - return FList.emptyList(); - } - } - - String nextChar = String.valueOf(myPattern[patternIndex]); - boolean upper = Character.isUpperCase(myPattern[patternIndex]); - - int fromIndex = nameIndex; - while (true) { - int next = StringUtil.indexOfIgnoreCase(name, nextChar, fromIndex); - if (next < 0) { - break; - } - if (upper && next > 0 && !Character.isUpperCase(name.charAt(next))) { - fromIndex = next + 1; - continue; - } - - FList ranges = matchName(name, patternIndex, next); - if (ranges != null) { - return ranges; - } - if (!maySkipNextChar) { - return null; - } - fromIndex = next + 1; - } - return null; - } - - @Nullable - private FList skipWords(String name, int patternIndex, int nameIndex) { - while (' ' == myPattern[patternIndex]) { - patternIndex++; - if (patternIndex == myPattern.length) { - return null; - } - } - - if (nameIndex == 0 || isWordStart(name, nameIndex)) { - FList ranges = matchName(name, patternIndex, nameIndex); - if (ranges != null) { - return ranges; - } - } - - boolean separatorInPattern = isWordSeparator(myPattern[patternIndex]); - int fromIndex = nameIndex; - while (fromIndex < name.length()) { - int next = separatorInPattern ? name.indexOf(myPattern[patternIndex], fromIndex) : nextWord(name, fromIndex); - if (next < 0) { - break; - } - - FList ranges = matchName(name, patternIndex, next); - if (ranges != null) { - return ranges; - } - fromIndex = next; - if (separatorInPattern) { - fromIndex++; - } - } - return null; - } - - public int matchingDegree(String name) { - Iterable iterable = matchingFragments(name); - if (iterable == null) return Integer.MIN_VALUE; - - int fragmentCount = 0; - int matchingCase = 0; - CharArrayCharSequence seq = new CharArrayCharSequence(myPattern); - int p = -1; - TextRange first = null; - for (TextRange range : iterable) { - if (first == null) { - first = range; - } - for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) { - char c = name.charAt(i); - p = StringUtil.indexOf(seq, c, p + 1, myPattern.length, false); - if (p < 0) { - break; - } - matchingCase += c == myPattern[p] ? 1 : 0; - } - fragmentCount++; - } - - int commonStart = 0; - while (commonStart < name.length() && commonStart < myPattern.length && name.charAt(commonStart) == myPattern[commonStart]) { - commonStart++; - } - - boolean prefixMatching = first != null && first.getStartOffset() == 0; - boolean middleWordStart = first != null && first.getStartOffset() > 0 && isWordStart(name, first.getStartOffset()); - - return -fragmentCount + matchingCase * 10 + commonStart + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 100; - } - - @Override - public boolean matches(String name) { - return matchingFragments(name) != null; - } - - @Nullable - public Iterable matchingFragments(String name) { - if (name.isEmpty()) { - return myPattern.length == 0 ? Collections.emptyList() : null; - } - - return matchName(name, 0, 0); - } - } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java index 3bbaed4fbef4..af08b7c08ae5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java @@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -1023,7 +1024,7 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton { new Task.Backgroundable(project, VcsBundle.message("show.diff.progress.title")) { @Override public void run(@NotNull ProgressIndicator indicator) { - LocalHistoryAction action = file != null ? startLocalHistoryAction(revision) : LocalHistoryAction.NULL; + final LocalHistoryAction action = file != null ? startLocalHistoryAction(revision) : LocalHistoryAction.NULL; final byte[] revisionContent; try { revisionContent = VcsHistoryUtil.loadRevisionContent(revision); @@ -1049,39 +1050,37 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton { return; } - try { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - CommandProcessor.getInstance().executeCommand(project, new Runnable() { - public void run() { - if (file != null && !file.isWritable()) { - if (ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(file).hasReadonlyFiles()) { - return; - } - } + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + try { + new WriteCommandAction.Simple(project) { + @Override + protected void run() throws Throwable { + if (file != null && + !file.isWritable() && + ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(file).hasReadonlyFiles()) { + return; + } - try { - write(revisionContent); - } catch (IOException e) { - Messages.showMessageDialog(VcsBundle.message("message.text.cannot.save.content", e.getLocalizedMessage()), - VcsBundle.message( "message.title.get.revision.content"), Messages.getErrorIcon()); - } - } - }, createGetActionTitle(revision), null); + try { + write(revisionContent); + } + catch (IOException e) { + Messages.showMessageDialog(VcsBundle.message("message.text.cannot.save.content", e.getLocalizedMessage()), + VcsBundle.message("message.title.get.revision.content"), Messages.getErrorIcon()); + } } - }); + }.execute(); + if (file != null) { + VcsDirtyScopeManager.getInstance(project).fileDirty(file); + } + } + finally { + action.finish(); } - }); - - if (file != null) { - VcsDirtyScopeManager.getInstance(project).fileDirty(file); } - } - finally { - action.finish(); - } + }); } }.queue(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java index 2e8d8380f5e7..d0a300d97200 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java @@ -49,7 +49,6 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.WaitForProgressToShow; -import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.OptionsDialog; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NonNls; @@ -581,19 +580,14 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { updateInfoTree.setBefore(myBefore); updateInfoTree.setAfter(myAfter); - // todo make temporal listener of changes reload - if (updateInfoTree != null) { - updateInfoTree.setCanGroupByChangeList(canGroupByChangelist(myVcsToVirtualFiles.keySet())); - final MessageBusConnection messageBusConnection = myProject.getMessageBus().connect(); - messageBusConnection.subscribe(CommittedChangesCache.COMMITTED_TOPIC, new CommittedChangesAdapter() { - public void incomingChangesUpdated(final List receivedChanges) { - if (receivedChanges != null) { - updateInfoTree.setChangeLists(receivedChanges); - messageBusConnection.disconnect(); - } + updateInfoTree.setCanGroupByChangeList(canGroupByChangelist(myVcsToVirtualFiles.keySet())); + myProject.getMessageBus().connect(updateInfoTree).subscribe(CommittedChangesCache.COMMITTED_TOPIC, new CommittedChangesAdapter() { + public void incomingChangesUpdated(final List receivedChanges) { + if (receivedChanges != null) { + updateInfoTree.setChangeLists(receivedChanges); } - }); - } + } + }); } public void onCancel() { diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpAssign.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpAssign.java new file mode 100644 index 000000000000..ca45c9670725 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpAssign.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ipp.opassign.assignment; + +class ByteOpassign { + + void foo(byte b) { + b += 1; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpAssign_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpAssign_after.java new file mode 100644 index 000000000000..af4441527704 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpAssign_after.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ipp.opassign.assignment; + +class ByteOpassign { + + void foo(byte b) { + b = (byte) (b + 1); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpassign.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpassign.java deleted file mode 100644 index ce6c0daca40f..000000000000 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpassign.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.siyeh.ipp.opassign.assignment; - -class ByteOpassign { - - void foo(byte b) { - b += 1; - } -} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpassign_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpassign_after.java deleted file mode 100644 index e4daf05d38e4..000000000000 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ByteOpassign_after.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.siyeh.ipp.opassign.assignment; - -class ByteOpassign { - - void foo(byte b) { - b = (byte) (b + 1); - } -} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpAssign.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpAssign.java new file mode 100644 index 000000000000..2e8a0e5ba7a5 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpAssign.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ipp.opassign.assignment; + +class DoubleOpassign { + + void foo(double d) { + d += 0.5; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpAssign_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpAssign_after.java new file mode 100644 index 000000000000..fe005f3c66d2 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpAssign_after.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ipp.opassign.assignment; + +class DoubleOpassign { + + void foo(double d) { + d = d + 0.5; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpassign.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpassign.java deleted file mode 100644 index fb159c964e3b..000000000000 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpassign.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.siyeh.ipp.opassign.assignment; - -class DoubleOpassign { - - void foo(double d) { - d += 0.5; - } -} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpassign_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpassign_after.java deleted file mode 100644 index fabb55a2a1c3..000000000000 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/DoubleOpassign_after.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.siyeh.ipp.opassign.assignment; - -class DoubleOpassign { - - void foo(double d) { - d = d + 0.5; - } -} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/StringOpAssign_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/StringOpAssign_after.java new file mode 100644 index 000000000000..feab030b8d20 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/StringOpAssign_after.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ipp.opassign.assignment; + +class StringOpassign { + + void foo(String s) { + s = s + 1.0; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/StringOpassign_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/StringOpassign_after.java deleted file mode 100644 index 5457c890258b..000000000000 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/StringOpassign_after.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.siyeh.ipp.opassign.assignment; - -class StringOpassign { - - void foo(String s) { - s = s + 1.0; - } -} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java index 953db64cab8b..7a3ff434924f 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java @@ -17,6 +17,7 @@ package com.intellij.android.designer.model; import com.intellij.android.designer.propertyTable.FragmentProperty; import com.intellij.android.designer.propertyTable.IdProperty; +import com.intellij.android.designer.propertyTable.JavadocParser; import com.intellij.android.designer.propertyTable.editors.ChooseClassDialog; import com.intellij.android.designer.propertyTable.editors.ResourceEditor; import com.intellij.designer.model.RadComponent; @@ -45,15 +46,17 @@ public class RadFragment extends RadViewComponent implements IConfigurableCompon setValue(fragment); } } - }, "Supply the name of the fragment class to instantiate."); + }, JavadocParser.build("name", "Supply the name of the fragment class to instantiate.")); private static final Property TAG_PROPERTY = new FragmentProperty("tag", new TextEditor(), - "Use device-admin as the root tag of the XML resource that\n" + - "describes a\n" + - " {@link android.app.admin.DeviceAdminReceiver}, which is\n" + - " referenced from its\n" + - " {@link android.app.admin.DeviceAdminReceiver#DEVICE_ADMIN_META_DATA}\n" + - " meta-data entry. Described here are the attributes that can be\n" + - " included in that tag."); + JavadocParser.build( + "tag", + "Use device-admin as the root tag of the XML resource that\n" + + "describes a\n" + + " {@link android.app.admin.DeviceAdminReceiver}, which is\n" + + " referenced from its\n" + + " {@link android.app.admin.DeviceAdminReceiver#DEVICE_ADMIN_META_DATA}\n" + + " meta-data entry. Described here are the attributes that can be\n" + + " included in that tag.")); private static final String NAME_KEY = "fragment.name"; @Override diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/CenterProperty.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/CenterProperty.java index a087b5511066..41c8ab813f2e 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/CenterProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/CenterProperty.java @@ -25,6 +25,7 @@ import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; +import com.intellij.android.designer.propertyTable.JavadocParser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,6 +36,8 @@ public class CenterProperty extends Property { private static final String[] COMBO_ITEMS = {"horizontal", "vertical", "both"}; private static final String[] ATTR_ITEMS = {"android:layout_centerHorizontal", "android:layout_centerVertical", "android:layout_centerInParent"}; + private static final String JAVA_DOC = + JavadocParser.build("layout:centerInParent", "Set centers this child horizontally or vertically within its parent."); private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null); private final PropertyEditor myEditor = new StringsComboEditor(COMBO_ITEMS); @@ -116,6 +119,6 @@ public class CenterProperty extends Property { @Override public String getJavadocText() { - return "Set centers this child horizontally or vertically within its parent."; + return JAVA_DOC; } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayout.java index 555ee8f16ad4..7130485d77f7 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayout.java @@ -22,6 +22,7 @@ import com.intellij.android.designer.designSurface.layout.relative.RelativeDecor import com.intellij.android.designer.model.PropertyParser; import com.intellij.android.designer.model.RadViewLayoutWithData; import com.intellij.android.designer.model.layout.actions.AllGravityAction; +import com.intellij.android.designer.propertyTable.JavadocParser; import com.intellij.designer.componentTree.TreeEditOperation; import com.intellij.designer.designSurface.*; import com.intellij.designer.designSurface.selection.ResizeSelectionDecorator; @@ -54,7 +55,9 @@ public class RadRelativeLayout extends RadViewLayoutWithData implements ILayoutD @Override public void configureProperties(List properties) { CompoundProperty alignComponent = - new CompoundProperty("layout:alignComponent", "Positions the edges of this view to the edges of the another view."); + new CompoundProperty("layout:alignComponent", + JavadocParser + .build("layout:alignComponent", "Positions the edges of this view to the edges of the another view.")); PropertyParser.moveProperties(properties, alignComponent, "layout:alignTop", "top:top", "layout:below", "top:bottom", @@ -68,7 +71,8 @@ public class RadRelativeLayout extends RadViewLayoutWithData implements ILayoutD properties.add(alignComponent); CompoundProperty alignParent = - new CompoundProperty("layout:alignParent", "Positions the edges of this view to the edges of the parent."); + new CompoundProperty("layout:alignParent", + JavadocParser.build("layout:alignParent", "Positions the edges of this view to the edges of the parent.")); PropertyParser.moveProperties(properties, alignParent, "layout:alignParentTop", "top", "layout:alignParentLeft", "left", diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java index f768db303a3c..46bdbda27916 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java @@ -41,6 +41,7 @@ public class AttributeProperty extends Property { protected final AttributeDefinition myDefinition; private final PropertyRenderer myRenderer; private final PropertyEditor myEditor; + private String myJavadocText; public AttributeProperty(@NotNull String name, @NotNull AttributeDefinition definition) { this(null, name, definition); @@ -137,6 +138,12 @@ public class AttributeProperty extends Property { @Override public String getJavadocText() { - return myDefinition.getDocValue(); + if (myJavadocText == null) { + String javadocText = myDefinition.getDocValue(); + if (javadocText != null) { + myJavadocText = JavadocParser.build(getName(), javadocText); + } + } + return myJavadocText; } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CustomViewProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CustomViewProperty.java index 8d02639ad0b0..17e4d2c2f96a 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CustomViewProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CustomViewProperty.java @@ -37,6 +37,7 @@ import java.util.List; * @author Alexander Lobas */ public class CustomViewProperty extends Property { + private static final String JAVA_DOC = JavadocParser.build("view:class", "The fully qualified name of the class."); private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null); private final PropertyEditor myEditor = new ResourceEditor(null, Collections.emptySet(), null) { @Override @@ -122,6 +123,6 @@ public class CustomViewProperty extends Property { @Override public String getJavadocText() { - return "The fully qualified name of the class."; + return JAVA_DOC; } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FlagProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FlagProperty.java index 200478958a73..461cfea30707 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FlagProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FlagProperty.java @@ -40,6 +40,7 @@ public class FlagProperty extends Property implements IPropert private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null); protected final AttributeDefinition myDefinition; protected final List> myOptions = new ArrayList>(); + private String myJavadocText; public FlagProperty(@NotNull String name, @NotNull AttributeDefinition definition) { super(null, name); @@ -163,7 +164,13 @@ public class FlagProperty extends Property implements IPropert @Override public String getJavadocText() { - return myDefinition.getDocValue(); + if (myJavadocText == null) { + String javadocText = myDefinition.getDocValue(); + if (javadocText != null) { + myJavadocText = JavadocParser.build(getName(), javadocText); + } + } + return myJavadocText; } ////////////////////////////////////////////////////////////////////////////////////////// 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 index 1835911adbfb..7d3a9f789577 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java @@ -41,6 +41,7 @@ public class IncludeLayoutProperty extends Property { public static ResourceType[] TYPES = new ResourceType[]{ResourceType.LAYOUT}; private static final Set FORMATS = EnumSet.of(AttributeFormat.Reference); public static final Property INSTANCE = new IncludeLayoutProperty(); + private static final String JAVA_DOC = JavadocParser.build(NAME, "Reference to the layout file you wish to include."); private final PropertyRenderer myRenderer = new ResourceRenderer(FORMATS); private final PropertyEditor myEditor = new ResourceEditor(TYPES, FORMATS, null); @@ -91,6 +92,6 @@ public class IncludeLayoutProperty extends Property { @Override public String getJavadocText() { - return "Reference to the layout file you wish to include."; + return JAVA_DOC; } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/JavadocParser.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/JavadocParser.java new file mode 100644 index 000000000000..422675316b7e --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/JavadocParser.java @@ -0,0 +1,86 @@ +/* + * 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.intellij.codeInsight.documentation.DocumentationManager; +import org.jetbrains.annotations.NotNull; + +/** + * @author Alexander Lobas + */ +public class JavadocParser { + private static final String[] TAGS = {"{see ", "{@see ", "{@link "}; + + @NotNull + public static String build(@NotNull String title, @NotNull String javadoc) { + StringBuilder buffer = new StringBuilder(); + + buffer.append(""); + buffer.append("

").append(title).append(" - "); + + for (String tag : TAGS) { + javadoc = convertLink(javadoc, tag); + } + + javadoc = javadoc.replaceAll("", ""); + javadoc = javadoc.replaceAll("", ""); + + buffer.append(javadoc); + + return buffer.append("").toString(); + } + + private static String convertLink(String javadoc, String tag) { + StringBuilder buffer = new StringBuilder(); + int length = javadoc.length(); + int start = 0; + + while (true) { + int index = javadoc.indexOf(tag, start); + + if (index == -1) { + buffer.append(javadoc.substring(start, length)); + break; + } + else { + buffer.append(javadoc.substring(start, index)); + + int linkStart = index + tag.length(); + int end = javadoc.indexOf('}', linkStart); + String linkValue = javadoc.substring(linkStart, end).trim(); + String href; + String text; + + int spaceIndex = linkValue.indexOf(' '); + if (spaceIndex != -1) { + href = linkValue.substring(0, spaceIndex); + text = linkValue.substring(spaceIndex + 1); + } + else { + href = text = linkValue; + } + + text = text.replace('#', '.'); + + DocumentationManager.createHyperlink(buffer, href, text, true); + + start = end + 1; + } + } + + return buffer.toString(); + } +} \ No newline at end of file diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy index d7d04ba87dab..7f9d3dddb6a9 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy @@ -92,7 +92,7 @@ class AndroidFacet extends Facet { } if (lookInContentRoot) { - module.contentRoots.each {String contentRoot -> + for (String contentRoot in module.contentRoots) { def absPath = FileUtil.toSystemIndependentName(contentRoot + relativePath) def f = new File(absPath) diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java index c982ef16a5ae..265845566c92 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java @@ -584,6 +584,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { if (!FileUtil.moveDirWithContent(tmpOutputDir, aptOutputDirectory)) { context.processMessage(new CompilerMessage(ANDROID_APT_COMPILER, BuildMessage.Kind.ERROR, AndroidJpsBundle .message("android.jps.errors.cannot.move.content", tmpOutputDir.getPath(), aptOutputDirectory.getPath()))); + success = false; continue; } markDirtyRecursively(aptOutputDirectory, context, ANDROID_APT_COMPILER); diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java index 350ba76c09e4..254d6b90beb2 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java @@ -27,7 +27,6 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jdom.Element; @@ -97,15 +96,10 @@ public class AndroidFacetConfiguration implements FacetConfiguration { } public void init(@NotNull Module module, @NotNull String baseDirectoryPath) { - String moduleDirPath = AndroidRootUtil.getModuleDirPath(module); - if (moduleDirPath == null) { + final String s = AndroidRootUtil.getPathRelativeToModuleDir(module, baseDirectoryPath); + if (s == null || s.length() == 0) { return; } - if (moduleDirPath.equals(baseDirectoryPath)) { - return; - } - - String s = FileUtil.getRelativePath(moduleDirPath, baseDirectoryPath, '/'); GEN_FOLDER_RELATIVE_PATH_APT = '/' + s + GEN_FOLDER_RELATIVE_PATH_APT; GEN_FOLDER_RELATIVE_PATH_AIDL = '/' + s + GEN_FOLDER_RELATIVE_PATH_AIDL; diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java b/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java index c24eed85f9a6..6eeb95037884 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java @@ -514,4 +514,16 @@ public class AndroidRootUtil { String moduleDirPath = getModuleDirPath(facet.getModule()); return moduleDirPath != null ? FileUtil.toSystemDependentName(moduleDirPath + path) : null; } + + @Nullable + public static String getPathRelativeToModuleDir(@NotNull Module module, @NotNull String path) { + String moduleDirPath = getModuleDirPath(module); + if (moduleDirPath == null) { + return null; + } + if (moduleDirPath.equals(path)) { + return ""; + } + return FileUtil.getRelativePath(moduleDirPath, path, '/'); + } } diff --git a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java index 2eaa9968d45e..7aa809d188e1 100644 --- a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java +++ b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java @@ -389,9 +389,13 @@ public abstract class AndroidFacetImporterBase extends FacetImporter 0 ? '/' + s + '/' : "/"; + configuration.RES_FOLDER_RELATIVE_PATH = s + AndroidMavenUtil.APK_LIB_ARTIFACT_RES_DIR; + configuration.LIBS_FOLDER_RELATIVE_PATH = s + AndroidMavenUtil.APK_LIB_ARTIFACT_NATIVE_LIBS_DIR; + configuration.MANIFEST_FILE_RELATIVE_PATH = s + AndroidMavenUtil.APK_LIB_ARTIFACT_MANIFEST_FILE; + } importSdkAndDependenciesForApklibArtifact(project, rootModelAdapter, apklibModuleModel, modelsProvider, mavenTree, artifact, mavenProject2ModuleName); diff --git a/plugins/devkit/src/dom/impl/IdeaPluginImpl.java b/plugins/devkit/src/dom/impl/IdeaPluginImpl.java index 198bcd3eb31a..bb213490e9c2 100644 --- a/plugins/devkit/src/dom/impl/IdeaPluginImpl.java +++ b/plugins/devkit/src/dom/impl/IdeaPluginImpl.java @@ -26,6 +26,10 @@ import org.jetbrains.idea.devkit.dom.IdeaPlugin; public abstract class IdeaPluginImpl implements IdeaPlugin { public String getPluginId() { final XmlTag tag = getXmlTag(); + if (tag == null) { + return null; + } + final XmlTag idTag = tag.findFirstSubTag("id"); if (idTag != null) { return idTag.getValue().getTrimmedText(); diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index 41db3cd4f414..4c4879a483ab 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -298,6 +298,9 @@ public class GitUtil { * @return git root for the file * @throws IllegalArgumentException if the file is not under git * @throws VcsException if the file is not under git + * + * @deprecated because uses the java.io.File. + * @use GitRepositoryManager#getRepositoryForFile(). */ public static VirtualFile getGitRoot(final FilePath filePath) throws VcsException { VirtualFile root = getGitRootOrNull(filePath); @@ -312,7 +315,11 @@ public class GitUtil { * * @param filePath a file path * @return git root for the file or null if the file is not under git + * + * @deprecated because uses the java.io.File. + * @use GitRepositoryManager#getRepositoryForFile(). */ + @Deprecated @Nullable public static VirtualFile getGitRootOrNull(final FilePath filePath) { return getGitRootOrNull(filePath.getIOFile()); @@ -322,6 +329,11 @@ public class GitUtil { return file != null && file.exists() && file.isDirectory() && new File(file, DOT_GIT).exists(); } + /** + * @deprecated because uses the java.io.File. + * @use GitRepositoryManager#getRepositoryForFile(). + */ + @Deprecated @Nullable public static VirtualFile getGitRootOrNull(final File file) { File root = file; @@ -337,6 +349,9 @@ public class GitUtil { * @param file the file to check * @return git root for the file * @throws VcsException if the file is not under git + * + * @deprecated because uses the java.io.File. + * @use GitRepositoryManager#getRepositoryForFile(). */ public static VirtualFile getGitRoot(@NotNull final VirtualFile file) throws VcsException { final VirtualFile root = gitRootOrNull(file); @@ -353,6 +368,9 @@ public class GitUtil { * * @param file the file to check * @return git root for the file or null if the file is not not under Git + * + * @deprecated because uses the java.io.File. + * @use GitRepositoryManager#getRepositoryForFile(). */ @Nullable public static VirtualFile gitRootOrNull(final VirtualFile file) { @@ -376,6 +394,9 @@ public class GitUtil { * @param project the project * @param vcs the git Vcs * @return the list of the roots + * + * @deprecated because uses the java.io.File. + * @use GitRepositoryManager#getRepositoryForFile(). */ @NotNull public static List getGitRoots(Project project, GitVcs vcs) throws VcsException { diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java index e0ee250f464e..c8129a70249f 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManagerImpl.java @@ -23,6 +23,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsRoot; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import git4idea.GitUtil; @@ -97,9 +98,13 @@ public class GitRepositoryManagerImpl extends AbstractProjectComponent implement @Override @Nullable public GitRepository getRepositoryForFile(@NotNull VirtualFile file) { - final VirtualFile vcsRoot = myVcsManager.getVcsRootFor(file); + final VcsRoot vcsRoot = myVcsManager.getVcsRootObjectFor(file); if (vcsRoot == null) { return null; } - return getRepositoryForRoot(vcsRoot); + if (!myVcs.equals(vcsRoot.vcs)) { + LOG.info(String.format("getRepositoryForFile returned non-Git (%s) root for file %s", vcsRoot.vcs.getDisplayName(), file)); + return null; + } + return getRepositoryForRoot(vcsRoot.path); } @Override diff --git a/plugins/git4idea/src/git4idea/status/GitChangeProvider.java b/plugins/git4idea/src/git4idea/status/GitChangeProvider.java index ab5754660478..94b3e69e7e47 100644 --- a/plugins/git4idea/src/git4idea/status/GitChangeProvider.java +++ b/plugins/git4idea/src/git4idea/status/GitChangeProvider.java @@ -62,6 +62,11 @@ public class GitChangeProvider implements ChangeProvider { final ChangelistBuilder builder, final ProgressIndicator progress, final ChangeListManagerGate addGate) throws VcsException { + final GitVcs vcs = GitVcs.getInstance(myProject); + if (vcs == null) { + // already disposed or not yet initialized => ignoring + return; + } final Collection affected = dirtyScope.getAffectedContentRootsWithCheck(); if (dirtyScope.getAffectedContentRoots().size() != affected.size()) { @@ -78,8 +83,10 @@ public class GitChangeProvider implements ChangeProvider { myFileDocumentManager, myVcsManager); for (VirtualFile root : roots) { GitChangesCollector collector = isNewGitChangeProviderAvailable() - ? GitNewChangesCollector.collect(myProject, myGit, myChangeListManager, dirtyScope, root) - : GitOldChangesCollector.collect(myProject, myChangeListManager, dirtyScope, root); + ? GitNewChangesCollector.collect(myProject, myGit, myChangeListManager, myVcsManager, + vcs, dirtyScope, root) + : GitOldChangesCollector.collect(myProject, myChangeListManager, myVcsManager, + vcs, dirtyScope, root); holder.changed(collector.getChanges()); for (Change file : collector.getChanges()) { builder.processChange(file, GitVcs.getKey()); @@ -90,11 +97,10 @@ public class GitChangeProvider implements ChangeProvider { } holder.feedBuilder(builder); } - } catch (VcsException e) {// most probably the error happened because git is not configured - final GitVcs vcs = GitVcs.getInstance(myProject); - if (vcs != null) { - vcs.getExecutableValidator().showNotificationOrThrow(e); - } + } + catch (VcsException e) { + // most probably the error happened because git is not configured + vcs.getExecutableValidator().showNotificationOrThrow(e); } } diff --git a/plugins/git4idea/src/git4idea/status/GitChangesCollector.java b/plugins/git4idea/src/git4idea/status/GitChangesCollector.java index 92058bc189d0..0d7869471475 100644 --- a/plugins/git4idea/src/git4idea/status/GitChangesCollector.java +++ b/plugins/git4idea/src/git4idea/status/GitChangesCollector.java @@ -17,13 +17,12 @@ package git4idea.status; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.FilePathImpl; +import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.changes.VcsDirtyScope; import com.intellij.openapi.vfs.VirtualFile; -import git4idea.GitUtil; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -37,18 +36,21 @@ import java.util.*; * @author Kirill Likhodedov */ abstract class GitChangesCollector { - protected final Project myProject; - protected final VirtualFile myVcsRoot; - private final ChangeListManager myChangeListManager; - private final VcsDirtyScope myDirtyScope; + @NotNull protected final Project myProject; + @NotNull protected final VirtualFile myVcsRoot; + + @NotNull private final VcsDirtyScope myDirtyScope; + @NotNull private final ChangeListManager myChangeListManager; + @NotNull private final ProjectLevelVcsManager myVcsManager; + @NotNull private AbstractVcs myVcs; - GitChangesCollector(@NotNull Project project, - @NotNull ChangeListManager changeListManager, - @NotNull VcsDirtyScope dirtyScope, - @NotNull VirtualFile vcsRoot) { + GitChangesCollector(@NotNull Project project, @NotNull ChangeListManager changeListManager, @NotNull ProjectLevelVcsManager vcsManager, + @NotNull AbstractVcs vcs, @NotNull VcsDirtyScope dirtyScope, @NotNull VirtualFile vcsRoot) { myProject = project; myChangeListManager = changeListManager; + myVcsManager = vcsManager; + myVcs = vcs; myDirtyScope = dirtyScope; myVcsRoot = vcsRoot; } @@ -80,27 +82,24 @@ abstract class GitChangesCollector { } if (includeChanges) { - try { - for (Change c : myChangeListManager.getChangesIn(myVcsRoot)) { - switch (c.getType()) { - case NEW: - case DELETED: - case MOVED: - if (c.getAfterRevision() != null) { - addToPaths(c.getAfterRevision().getFile(), allPaths); - } - if (c.getBeforeRevision() != null) { - addToPaths(c.getBeforeRevision().getFile(), allPaths); - } - case MODIFICATION: - default: - // do nothing - } + for (Change c : myChangeListManager.getChangesIn(myVcsRoot)) { + switch (c.getType()) { + case NEW: + case DELETED: + case MOVED: + ContentRevision afterRevision = c.getAfterRevision(); + if (afterRevision != null) { + addToPaths(afterRevision.getFile(), allPaths); + } + ContentRevision beforeRevision = c.getBeforeRevision(); + if (beforeRevision != null) { + addToPaths(beforeRevision.getFile(), allPaths); + } + case MODIFICATION: + default: + // do nothing } } - catch (Exception t) { - // ignore exceptions - } } removeCommonParents(allPaths); @@ -114,9 +113,9 @@ abstract class GitChangesCollector { } protected void addToPaths(FilePath pathToAdd, List paths) { - File file = pathToAdd.getIOFile(); - if (myVcsRoot.equals(GitUtil.getGitRootOrNull(file))) { - paths.add(file.getPath()); + VcsRoot fileRoot = myVcsManager.getVcsRootObjectFor(pathToAdd); + if (fileRoot != null && fileRoot.vcs != null && fileRoot.vcs.equals(myVcs) && myVcsRoot.equals(fileRoot.path)) { + paths.add(pathToAdd.getPath()); } } diff --git a/plugins/git4idea/src/git4idea/status/GitNewChangesCollector.java b/plugins/git4idea/src/git4idea/status/GitNewChangesCollector.java index 983e493813cf..6d1afc991059 100644 --- a/plugins/git4idea/src/git4idea/status/GitNewChangesCollector.java +++ b/plugins/git4idea/src/git4idea/status/GitNewChangesCollector.java @@ -18,9 +18,7 @@ package git4idea.status; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.FileStatus; -import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ContentRevision; @@ -70,8 +68,9 @@ class GitNewChangesCollector extends GitChangesCollector { */ @NotNull static GitNewChangesCollector collect(@NotNull Project project, @NotNull Git git, @NotNull ChangeListManager changeListManager, + @NotNull ProjectLevelVcsManager vcsManager, @NotNull AbstractVcs vcs, @NotNull VcsDirtyScope dirtyScope, @NotNull VirtualFile vcsRoot) throws VcsException { - return new GitNewChangesCollector(project, git, changeListManager, dirtyScope, vcsRoot); + return new GitNewChangesCollector(project, git, changeListManager, vcsManager, vcs, dirtyScope, vcsRoot); } @Override @@ -87,9 +86,10 @@ class GitNewChangesCollector extends GitChangesCollector { } private GitNewChangesCollector(@NotNull Project project, @NotNull Git git, @NotNull ChangeListManager changeListManager, + @NotNull ProjectLevelVcsManager vcsManager, @NotNull AbstractVcs vcs, @NotNull VcsDirtyScope dirtyScope, @NotNull VirtualFile vcsRoot) throws VcsException { - super(project, changeListManager, dirtyScope, vcsRoot); + super(project, changeListManager, vcsManager, vcs, dirtyScope, vcsRoot); myGit = git; myRepository = GitUtil.getRepositoryManager(myProject).getRepositoryForRoot(vcsRoot); diff --git a/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java b/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java index 52ed9458f353..518efac8ca8d 100644 --- a/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java +++ b/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java @@ -16,9 +16,7 @@ package git4idea.status; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.FileStatus; -import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ContentRevision; @@ -104,11 +102,10 @@ class GitOldChangesCollector extends GitChangesCollector { * This may be lengthy. */ @NotNull - static GitOldChangesCollector collect(@NotNull Project project, - @NotNull ChangeListManager changeListManager, - @NotNull VcsDirtyScope dirtyScope, - @NotNull VirtualFile vcsRoot) throws VcsException { - return new GitOldChangesCollector(project, changeListManager, dirtyScope, vcsRoot); + static GitOldChangesCollector collect(@NotNull Project project, @NotNull ChangeListManager changeListManager, + @NotNull ProjectLevelVcsManager vcsManager, @NotNull AbstractVcs vcs, + @NotNull VcsDirtyScope dirtyScope, @NotNull VirtualFile vcsRoot) throws VcsException { + return new GitOldChangesCollector(project, changeListManager, vcsManager, vcs, dirtyScope, vcsRoot); } @NotNull @@ -123,11 +120,10 @@ class GitOldChangesCollector extends GitChangesCollector { return myChanges; } - private GitOldChangesCollector(@NotNull Project project, - @NotNull ChangeListManager changeListManager, - @NotNull VcsDirtyScope dirtyScope, + private GitOldChangesCollector(@NotNull Project project, @NotNull ChangeListManager changeListManager, + @NotNull ProjectLevelVcsManager vcsManager, @NotNull AbstractVcs vcs, @NotNull VcsDirtyScope dirtyScope, @NotNull VirtualFile vcsRoot) throws VcsException { - super(project, changeListManager, dirtyScope, vcsRoot); + super(project, changeListManager, vcsManager, vcs, dirtyScope, vcsRoot); updateIndex(); collectUnmergedAndUnversioned(); collectDiffChanges(); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java index c11a585ba6dc..2f2b7da84e3a 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java @@ -28,11 +28,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.popup.NotLookupOrSearchCondition; import java.awt.*; @@ -85,13 +87,22 @@ public class ShowJavadoc extends AnAction implements IPropertyTableAction { callback.doWhenProcessed(new Runnable() { public void run() { - final JBPopup hint = + JBPopup hint = JBPopupFactory.getInstance().createComponentPopupBuilder(component, component) + .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE) + .setProject(project) .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false) .setResizable(true) .setMovable(true) .setRequestFocus(true) .setTitle(DesignerBundle.message("designer.properties.javadoc.title", property.getName())) + .setCancelCallback(new Computable() { + @Override + public Boolean compute() { + Disposer.dispose(component); + return Boolean.TRUE; + } + }) .createPopup(); component.setHint(hint); Disposer.register(hint, component); diff --git a/plugins/ui-designer/ui-designer-new/src/messages/DesignerBundle.properties b/plugins/ui-designer/ui-designer-new/src/messages/DesignerBundle.properties index f105d74fd4cf..aeb0e5ad1812 100644 --- a/plugins/ui-designer/ui-designer-new/src/messages/DesignerBundle.properties +++ b/plugins/ui-designer/ui-designer-new/src/messages/DesignerBundle.properties @@ -8,7 +8,7 @@ command.set.property.value=Set Property Value designer.properties.title=Properties designer.properties.show.expert=Show expert properties designer.properties.show.javadoc=Show Documentation -designer.properties.javadoc.title=Documentation for {0} property +designer.properties.javadoc.title=Documentation for {0} property designer.properties.restore_default=Restore default value designer.properties.column1=Property designer.properties.column2=Value