From 3c6b40759b28b52b67a0e1fb6cf837a5fb548026 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 8 Apr 2016 10:36:21 +0200 Subject: [PATCH] [java] adds PsiModifierList.hasModifierProperty() augmentation point (IDEA-153706) --- .../psi/augment/PsiAugmentProvider.java | 38 +++++++++- .../psi/impl/source/PsiModifierListImpl.java | 8 ++- .../daemonCodeAnalyzer/augment/LombokVal.java | 3 + .../daemon/PsiAugmentProviderTest.java | 71 ++++++++++++------- 4 files changed, 89 insertions(+), 31 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java index d93c408f4e99..0d2fa85b9671 100644 --- a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java +++ b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiType; import com.intellij.psi.PsiTypeElement; import com.intellij.util.Processor; @@ -35,8 +36,10 @@ import java.util.Collections; import java.util.List; /** - * An extension that enables plugins to alter a behavior of Java PSI elements. - * During indexing, only {@link DumbAware} augment providers are run. + * Some code is not what it seems to be! + * This extension allows plugins augment a reality alter a behavior of Java PSI elements. + *

+ * N.B. during indexing, only {@link DumbAware} providers are run. */ public abstract class PsiAugmentProvider { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.lang.psiAugmentProvider"); @@ -66,6 +69,16 @@ public abstract class PsiAugmentProvider { return null; } + /** + * Intercepts {@link PsiModifierList#hasModifierProperty(String)}, so that plugins can add imaginary modifiers or hide existing ones. + * + * @since 2016.2 + */ + @Nullable + protected Boolean hasModifierProperty(@NotNull PsiModifierList modifierList, @NotNull String name) { + return null; + } + // // @@ -106,6 +119,27 @@ public abstract class PsiAugmentProvider { return result.get(); } + @Nullable + public static Boolean checkModifierProperty(@NotNull final PsiModifierList modifierList, @NotNull final String name) { + final Ref result = Ref.create(); + + forEach(modifierList.getProject(), new Processor() { + @Override + public boolean process(PsiAugmentProvider provider) { + Boolean property = provider.hasModifierProperty(modifierList, name); + if (property != null) { + result.set(property); + return false; + } + else { + return true; + } + } + }); + + return result.get(); + } + private static void forEach(Project project, Processor processor) { for (PsiAugmentProvider provider : Extensions.getExtensions(EP_NAME)) { if (!DumbService.isDumb(project) || DumbService.isDumbAware(provider)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java index 645343cce0f5..1d486c9dd58d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java @@ -68,7 +68,10 @@ public class PsiModifierListImpl extends JavaStubPsiElement @Override public boolean hasModifierProperty(@NotNull String name) { - final PsiModifierListStub stub = getStub(); + Boolean augmentation = PsiAugmentProvider.checkModifierProperty(this, name); + if (augmentation != null) return augmentation; + + PsiModifierListStub stub = getStub(); if (stub != null) { return ModifierFlags.hasModifierProperty(name, stub.getModifiersMask()); } @@ -300,7 +303,8 @@ public class PsiModifierListImpl extends JavaStubPsiElement } } + @Override public String toString(){ return "PsiModifierList:" + getText(); } -} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/augment/LombokVal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/augment/LombokVal.java index 5d2fa941c47c..0d67b6b0edbb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/augment/LombokVal.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/augment/LombokVal.java @@ -21,5 +21,8 @@ class Test { for (val v : a) { String vStr = v; } + + val x = 0; + x++; } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/PsiAugmentProviderTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/PsiAugmentProviderTest.java index 8895f843c855..dbe333d6d074 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/PsiAugmentProviderTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/PsiAugmentProviderTest.java @@ -69,38 +69,34 @@ public class PsiAugmentProviderTest extends LightCodeInsightFixtureTestCase { @Override protected PsiType inferType(@NotNull PsiTypeElement typeElement) { PsiElement parent = typeElement.getParent(); - if (parent instanceof PsiLocalVariable && ((PsiLocalVariable)parent).getInitializer() != null || - parent instanceof PsiParameter && ((PsiParameter)parent).getDeclarationScope() instanceof PsiForeachStatement) { - String text = typeElement.getText(); - if (LOMBOK_VAL_SHORT_NAME.equals(text) || LOMBOK_VAL_FQN.equals(text)) { - PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement(); - if (referenceElement != null) { - PsiElement resolve = referenceElement.resolve(); - if (resolve instanceof PsiClass) { - if (parent instanceof PsiLocalVariable) { - PsiExpression initializer = ((PsiVariable)parent).getInitializer(); - assertNotNull(initializer); - PsiType initializerType = initializer.getType(); - if (initializer instanceof PsiNewExpression) { - PsiJavaCodeReferenceElement reference = ((PsiNewExpression)initializer).getClassOrAnonymousClassReference(); - if (reference != null) { - PsiReferenceParameterList parameterList = reference.getParameterList(); - if (parameterList != null) { - PsiTypeElement[] elements = parameterList.getTypeParameterElements(); - if (elements.length == 1 && elements[0].getType() instanceof PsiDiamondType) { - return TypeConversionUtil.erasure(initializerType); - } + if (isLombokVal(parent)) { + PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement(); + if (referenceElement != null) { + PsiElement resolve = referenceElement.resolve(); + if (resolve instanceof PsiClass) { + if (parent instanceof PsiLocalVariable) { + PsiExpression initializer = ((PsiVariable)parent).getInitializer(); + assertNotNull(initializer); + PsiType initializerType = initializer.getType(); + if (initializer instanceof PsiNewExpression) { + PsiJavaCodeReferenceElement reference = ((PsiNewExpression)initializer).getClassOrAnonymousClassReference(); + if (reference != null) { + PsiReferenceParameterList parameterList = reference.getParameterList(); + if (parameterList != null) { + PsiTypeElement[] elements = parameterList.getTypeParameterElements(); + if (elements.length == 1 && elements[0].getType() instanceof PsiDiamondType) { + return TypeConversionUtil.erasure(initializerType); } } } - return initializerType; } + return initializerType; + } - PsiForeachStatement foreachStatement = (PsiForeachStatement)((PsiParameter)parent).getDeclarationScope(); - PsiExpression iteratedValue = foreachStatement.getIteratedValue(); - if (iteratedValue != null) { - return JavaGenericsUtil.getCollectionItemType(iteratedValue); - } + PsiForeachStatement foreachStatement = (PsiForeachStatement)((PsiParameter)parent).getDeclarationScope(); + PsiExpression iteratedValue = foreachStatement.getIteratedValue(); + if (iteratedValue != null) { + return JavaGenericsUtil.getCollectionItemType(iteratedValue); } } } @@ -108,5 +104,26 @@ public class PsiAugmentProviderTest extends LightCodeInsightFixtureTestCase { return null; } + + @Nullable + @Override + protected Boolean hasModifierProperty(@NotNull PsiModifierList modifierList, @NotNull String name) { + return (PsiModifier.FINAL.equals(name) && isLombokVal(modifierList.getParent())) ? Boolean.TRUE : null; + } + + private static boolean isLombokVal(PsiElement variable) { + if (variable instanceof PsiLocalVariable && ((PsiLocalVariable)variable).getInitializer() != null || + variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { + PsiTypeElement typeElement = ((PsiVariable)variable).getTypeElement(); + if (typeElement != null) { + String text = typeElement.getText(); + if (LOMBOK_VAL_SHORT_NAME.equals(text) || LOMBOK_VAL_FQN.equals(text)) { + return true; + } + } + } + + return false; + } } } \ No newline at end of file