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