From 8fd66c2785104743e6747b2d03fa0a72010caba6 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Thu, 3 Jun 2010 15:03:23 +0400 Subject: [PATCH 1/3] remove duplicates from find usages of groovy properties & accessors read-write support for groovy property usages --- .../src/com/intellij/psi/util/PsiUtil.java | 12 +-- .../com/intellij/psi/util/PsiTreeUtil.java | 13 +++ plugins/groovy/src/META-INF/plugin.xml | 2 + .../GroovyFindUsagesHandlerFactory.java | 96 +++++++++++++++++++ .../GroovyReadWriteAccessDetector.java | 67 +++++++++++++ .../GrReferenceExpressionImpl.java | 27 +----- .../plugins/groovy/lang/psi/util/PsiUtil.java | 21 +++- resources/src/META-INF/IdeaPlugin.xml | 2 +- 8 files changed, 205 insertions(+), 35 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyFindUsagesHandlerFactory.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyReadWriteAccessDetector.java diff --git a/java/openapi/src/com/intellij/psi/util/PsiUtil.java b/java/openapi/src/com/intellij/psi/util/PsiUtil.java index f3b41b26e7a7..1ac2d4100b5c 100644 --- a/java/openapi/src/com/intellij/psi/util/PsiUtil.java +++ b/java/openapi/src/com/intellij/psi/util/PsiUtil.java @@ -53,9 +53,9 @@ public final class PsiUtil extends PsiUtilBase { private PsiUtil() {} public static boolean isOnAssignmentLeftHand(PsiExpression expr) { - PsiElement parent = expr.getParent(); - return parent instanceof PsiAssignmentExpression - && expr.equals(((PsiAssignmentExpression) parent).getLExpression()); + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, PsiParenthesizedExpression.class); + return parent instanceof PsiAssignmentExpression && + PsiTreeUtil.isAncestor(((PsiAssignmentExpression)parent).getLExpression(), expr, false); } public static boolean isAccessibleFromPackage(@NotNull PsiModifierListOwner element, @NotNull PsiPackage aPackage) { @@ -66,7 +66,7 @@ public final class PsiUtil extends PsiUtilBase { public static boolean isAccessedForWriting(PsiExpression expr) { if (isOnAssignmentLeftHand(expr)) return true; - PsiElement parent = expr.getParent(); + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, PsiParenthesizedExpression.class); if (parent instanceof PsiPrefixExpression) { IElementType tokenType = ((PsiPrefixExpression) parent).getOperationTokenType(); return tokenType == JavaTokenType.PLUSPLUS || tokenType == JavaTokenType.MINUSMINUS; @@ -81,9 +81,9 @@ public final class PsiUtil extends PsiUtilBase { } public static boolean isAccessedForReading(PsiExpression expr) { - PsiElement parent = expr.getParent(); + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, PsiParenthesizedExpression.class); return !(parent instanceof PsiAssignmentExpression) || - !expr.equals(((PsiAssignmentExpression)parent).getLExpression()) || + !PsiTreeUtil.isAncestor(((PsiAssignmentExpression)parent).getLExpression(), expr, false) || ((PsiAssignmentExpression)parent).getOperationSign().getTokenType() != JavaTokenType.EQ; } diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java b/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java index b47dc9f8958f..217679658281 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java @@ -322,6 +322,19 @@ public class PsiTreeUtil { return null; } + @Nullable + public static PsiElement skipParentsOfType(@Nullable PsiElement element, @NotNull Class... parentClasses) { + if (element == null) return null; + NextSibling: + for (PsiElement e = element.getParent(); e != null; e = e.getParent()) { + for (Class aClass : parentClasses) { + if (instanceOf(aClass, e)) continue NextSibling; + } + return e; + } + return null; + } + @Nullable public static T getParentOfType(PsiElement element, @NotNull Class... classes) { if (element == null) return null; diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 8fd0671cfb07..32f213571706 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -116,6 +116,8 @@ + + elements = new ArrayList(); + if (getter != null) { + elements.addAll(Arrays.asList(SuperMethodWarningUtil.checkSuperMethods(getter, ACTION_STRING))); + } + if (setter != null) { + elements.addAll(Arrays.asList(SuperMethodWarningUtil.checkSuperMethods(setter, ACTION_STRING))); + } + return elements.toArray(new PsiElement[elements.size()]); + } else { + return PsiElement.EMPTY_ARRAY; + } + } + } + return super.getSecondaryElements(); + } + }; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyReadWriteAccessDetector.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyReadWriteAccessDetector.java new file mode 100644 index 000000000000..3e85535545bd --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyReadWriteAccessDetector.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.findUsages; + +import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiReference; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +/** + * @author Maxim.Medvedev + */ +public class GroovyReadWriteAccessDetector extends ReadWriteAccessDetector{ + @Override + public boolean isReadWriteAccessible(PsiElement element) { + return element instanceof GrVariable; + } + + @Override + public boolean isDeclarationWriteAccess(PsiElement element) { + if (element instanceof GrVariable && ((GrVariable)element).getInitializerGroovy() != null) { + return true; + } + return false; + } + + @Override + public Access getReferenceAccess(PsiElement referencedElement, PsiReference reference) { + return getExpressionAccess(reference.getElement()); + } + + @Override + public Access getExpressionAccess(PsiElement expression) { + if (!(expression instanceof GrExpression)) return Access.Read; + GrExpression expr = (GrExpression) expression; + boolean readAccess = PsiUtil.isAccessedForReading(expr); + boolean writeAccess = PsiUtil.isAccessedForWriting(expr); + if (!writeAccess && expr instanceof GrReferenceExpression) { + //when searching usages of fields, should show all found setters as a "only write usage" + PsiElement actualReferee = ((GrReferenceExpression) expr).resolve(); + if (actualReferee instanceof PsiMethod && GroovyPropertyUtils.isSimplePropertySetter((PsiMethod)actualReferee)) { + writeAccess = true; + readAccess = false; + } + } + if (writeAccess && readAccess) return Access.ReadWrite; + return writeAccess ? Access.Write : Access.Read; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index c5a2157a9f7c..362ed5658041 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -18,7 +18,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; @@ -55,7 +54,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; @@ -684,30 +682,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } public boolean isReferenceTo(PsiElement element) { - if (element instanceof PsiMethod && GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod) element)) { - final PsiElement target = resolve(); - if (element instanceof GrAccessorMethod && getManager().areElementsEquivalent(((GrAccessorMethod)element).getProperty(), target)) { - return false; - } - - return getManager().areElementsEquivalent(element, target); - } - - if (element instanceof GrField && ((GrField) element).isProperty()) { - final PsiElement target = resolve(); - if (getManager().areElementsEquivalent(element, target)) { - return true; - } - - for (final GrAccessorMethod getter : ((GrField)element).getGetters()) { - if (getManager().areElementsEquivalent(getter, target)) { - return true; - } - } - return getManager().areElementsEquivalent(((GrField)element).getSetter(), target); - } - - if (element instanceof PsiNamedElement && Comparing.equal(((PsiNamedElement) element).getName(), getReferenceName())) { + if (element instanceof PsiNamedElement) { return getManager().areElementsEquivalent(element, resolve()); } return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 25ba5ef6beb7..16c9961f9f2b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -27,6 +27,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; @@ -109,11 +110,11 @@ public class PsiUtil { public static boolean isLValue(GroovyPsiElement element) { if (element instanceof GrExpression) { - PsiElement parent = element.getParent(); + PsiElement parent = PsiTreeUtil.skipParentsOfType(element, GrParenthesizedExpression.class); if (parent instanceof GrListOrMap && !((GrListOrMap)parent).isMap()) { return isLValue((GroovyPsiElement)parent); } - return parent instanceof GrAssignmentExpression && element.equals(((GrAssignmentExpression)parent).getLValue()); + return parent instanceof GrAssignmentExpression && PsiTreeUtil.isAncestor(((GrAssignmentExpression)parent).getLValue(), element, false); } return false; } @@ -777,4 +778,20 @@ public class PsiUtil { return constructorResults.toArray(new GroovyResolveResult[constructorResults.size()]); } + + public static boolean isAccessedForReading(GrExpression expr) { + return !isLValue(expr); + } + + public static boolean isAccessedForWriting(GrExpression expr) { + if (isLValue(expr)) return true; + + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, GrParenthesizedExpression.class); + + if (parent instanceof GrUnaryExpression) { + IElementType tokenType = ((GrUnaryExpression)parent).getOperationTokenType(); + return tokenType == GroovyTokenTypes.mINC || tokenType == GroovyTokenTypes.mDEC; + } + return false; + } } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index e8f1cd62632d..a7234bfd4341 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1038,7 +1038,7 @@ - + From c5e7ad1cd02241a858b49e1f0a0998a38220c5ad Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Thu, 3 Jun 2010 15:46:43 +0400 Subject: [PATCH 2/3] Resolve symlinks to temp directory so VFS can work correctly there (TypeCookTests used to fail on Macs because of this issue). --- .../testFramework/PlatformTestCase.java | 1 + .../intellij/openapi/util/io/FileUtil.java | 22 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index ab02cc286ec9..d64219b951eb 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -589,6 +589,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro field.setAccessible(true); field.set(ioFile, null); + FileUtil.resetCanonicalTempPathCache(); } catch (NoSuchFieldException ignore) { // field was removed in JDK 1.6.0_12 diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index 8f4e9c38386c..cf34d2047a14 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -48,7 +48,8 @@ public class FileUtil { }; // do not use channels to copy files larger than 5 Mb because of possible MapFailed error - private static final long CHANNELS_COPYING_LIMIT = 5L * 1024L * 1024L; + private static final long CHANNELS_COPYING_LIMIT = 5L * 1024L * 1024L; + private static String ourCanonicalTempPathCache = null; //private static final byte[] BUFFER = new byte[1024 * 20]; @@ -369,7 +370,24 @@ public class FileUtil { } public static String getTempDirectory() { - return System.getProperty("java.io.tmpdir"); + if (ourCanonicalTempPathCache == null) { + ourCanonicalTempPathCache = calcCanonicalTempPath(); + } + return ourCanonicalTempPathCache; + } + + public static void resetCanonicalTempPathCache() { + ourCanonicalTempPathCache = null; + } + + private static String calcCanonicalTempPath() { + final String prop = System.getProperty("java.io.tmpdir"); + try { + return new File(prop).getCanonicalPath(); + } + catch (IOException e) { + return prop; + } } public static void asyncDelete(@NotNull File file) { From f47148a242ba83518764b38f4cfa3bc8cd76b3c9 Mon Sep 17 00:00:00 2001 From: "Rustam.Vishnyakov" Date: Thu, 3 Jun 2010 15:33:17 +0400 Subject: [PATCH 3/3] Fix for EA-20311: split HTML comment if it contains outer language elements --- .../intellij/psi/formatter/xml/XmlBlock.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java b/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java index d0e501a41320..656292521664 100644 --- a/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java +++ b/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java @@ -25,6 +25,7 @@ import com.intellij.psi.TokenType; import com.intellij.psi.formatter.FormatterUtil; import com.intellij.psi.formatter.common.AbstractBlock; import com.intellij.psi.impl.source.SourceTreeToPsiMap; +import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlElementType; @@ -128,23 +129,23 @@ public class XmlBlock extends AbstractXmlBlock { private List splitComment() { - if (myNode.getElementType() != XmlElementType.XML_COMMENT) return null; - // - // Do not build subblocks for comment-only node. - if (myNode.getFirstChildNode() != null && - myNode.getFirstChildNode().getElementType() == XmlElementType.XML_COMMENT_START && - myNode.getLastChildNode().getElementType() == XmlElementType.XML_COMMENT_END) { - return EMPTY; - } + if (myNode.getElementType() != XmlElementType.XML_COMMENT) return EMPTY; final ArrayList result = new ArrayList(3); - final ArrayList commentBlocks = new ArrayList(3); ASTNode child = myNode.getFirstChildNode(); + boolean hasOuterLangElements = false; while (child != null) { - IElementType childType = child.getElementType(); + if (child instanceof OuterLanguageElement) { + hasOuterLangElements = true; + } result.add(new XmlBlock(child, null, null, myXmlFormattingPolicy, getChildIndent(), null)); child = child.getTreeNext(); } - return result; + if (hasOuterLangElements) { + return result; + } + else { + return EMPTY; + } } protected @Nullable Wrap getDefaultWrap(ASTNode node) {