diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java index 30e3b1b30529..985395dbc2e5 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.lang.psi; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; @@ -44,4 +45,7 @@ public interface GroovyFile extends GroovyFileBase { @Nullable PsiType getInferredScriptReturnType(); + + @NotNull + GrVariableDeclaration[] getAnnotatedScriptDeclarations(); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java index 04e6261c6946..40fbeef261a1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java @@ -178,6 +178,9 @@ public abstract class GroovyPsiElementFactory implements JVMElementFactory { @NotNull public abstract GrVariableDeclaration createVariableDeclaration(@Nullable String[] modifiers, @Nullable String initializer, @Nullable PsiType type, String... identifiers); + @NotNull + public abstract GrVariableDeclaration createVariableDeclarationFromText(@NotNull String text, @Nullable PsiElement context); + @NotNull public abstract GrEnumConstant createEnumConstantFromText(@NotNull String text); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrVariableDeclaration.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrVariableDeclaration.java index b47d60a4b967..02cfee85a596 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrVariableDeclaration.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrVariableDeclaration.java @@ -30,6 +30,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; * @date: 27.03.2007 */ public interface GrVariableDeclaration extends GrStatement, GrMembersDeclaration { + GrVariableDeclaration[] EMPTY_ARRAY = new GrVariableDeclaration[0]; ArrayFactory ARRAY_FACTORY = count -> new GrVariableDeclaration[count]; @Nullable diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index 1989237ce5d9..f8820e328fc4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -41,6 +41,7 @@ import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrTopLevelDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; @@ -534,6 +535,16 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { return this; } + @NotNull + @Override + public GrVariableDeclaration[] getAnnotatedScriptDeclarations() { + StubElement stub = getStub(); + if (stub instanceof GrFileStub) { + return ((GrFileStub)stub).getAnnotatedScriptDeclarations(); + } + return PsiImplUtil.getAnnotatedScriptDesclarations(this); + } + @Override public String toString() { if (ApplicationManager.getApplication().isUnitTestMode()){ diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java index 06c4221ebb77..882c0a83cb96 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java @@ -296,6 +296,13 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { return statement; } + @NotNull + @Override + public GrVariableDeclaration createVariableDeclarationFromText(@NotNull String text, @Nullable PsiElement context) { + final GroovyFile file = createGroovyFileChecked(text, false, context); + return ((GrVariableDeclaration)file.getTopStatements()[0]); + } + @NotNull @Override public GrEnumConstant createEnumConstantFromText(@NotNull String text) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java index 35c4a4c33544..f4bd48a68243 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java @@ -36,6 +36,7 @@ import com.intellij.reference.SoftReference; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ReflectionUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.StringFactory; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -69,6 +70,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrI import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -152,7 +154,7 @@ public class PsiImplUtil { } } - + GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(oldExpr.getProject()); if (oldParent instanceof GrStringInjection) { if (newExpr instanceof GrString || newExpr instanceof GrLiteral && ((GrLiteral)newExpr).getValue() instanceof String) { @@ -165,7 +167,7 @@ public class PsiImplUtil { return ((GrExpression)statements[0]).replaceWithExpression(newExpr, removeUnnecessaryParentheses); } } - + if (PsiTreeUtil.getParentOfType(oldExpr, GrStringInjection.class, false, GrCodeBlock.class) != null) { final GrStringInjection stringInjection = PsiTreeUtil.getParentOfType(oldExpr, GrStringInjection.class); GrStringUtil.wrapInjection(stringInjection); @@ -173,7 +175,7 @@ public class PsiImplUtil { final PsiElement replaced = oldExpr.replaceWithExpression(newExpr, removeUnnecessaryParentheses); return (GrExpression)replaced; } - + //check priorities if (oldParent instanceof GrExpression && !(oldParent instanceof GrParenthesizedExpression)) { GrExpression addedParenth = addParenthesesIfNeeded(newExpr, oldExpr, (GrExpression)oldParent); @@ -1022,4 +1024,30 @@ public class PsiImplUtil { substitutor, result.isAccessible(), result.isStaticsOK(), result.isInvokedOnProperty(), result.isValidResult()); } + + @NotNull + static GrVariableDeclaration[] getAnnotatedScriptDesclarations(@NotNull GroovyFile file) { + if (!file.isScript()) return GrVariableDeclaration.EMPTY_ARRAY; + List result = ContainerUtil.newArrayList(); + file.accept(new GroovyRecursiveElementVisitor() { + + @Override + public void visitVariableDeclaration(@NotNull GrVariableDeclaration declaration) { + if (declaration.getModifierList().getAnnotations().length > 0) { + result.add(declaration); + } + } + + @Override + public void visitMethod(@NotNull GrMethod method) { + //skip methods + } + + @Override + public void visitTypeDefinition(@NotNull GrTypeDefinition typeDefinition) { + //skip type defs + } + }); + return result.toArray(GrVariableDeclaration.EMPTY_ARRAY); + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java index d819ae355419..d2a35d2f157e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java @@ -17,20 +17,27 @@ package org.jetbrains.plugins.groovy.lang.psi.stubs; import com.intellij.psi.stubs.PsiFileStubImpl; import com.intellij.psi.tree.IStubFileElementType; +import com.intellij.reference.SoftReference; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.parser.GroovyParserDefinition; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; /** * @author ilyas */ public class GrFileStub extends PsiFileStubImpl { - private final String[] myAnnotations; + private final @NotNull String[] myAnnotations; private final StringRef myName; private final boolean isScript; + private final @NotNull String[] myDeclarationStrings; + + private SoftReference myDeclarations; public GrFileStub(GroovyFile file) { super(file); @@ -39,16 +46,23 @@ public class GrFileStub extends PsiFileStubImpl { final GrPackageDefinition definition = file.getPackageDefinition(); if (definition != null) { myAnnotations = GrStubUtils.getAnnotationNames(definition); - } else { + } + else { myAnnotations = ArrayUtil.EMPTY_STRING_ARRAY; } + myDeclarationStrings = ContainerUtil.map( + file.getAnnotatedScriptDeclarations(), + declaration -> declaration.getText(), + ArrayUtil.EMPTY_STRING_ARRAY + ); } - public GrFileStub(StringRef name, boolean isScript, String[] annotations) { + public GrFileStub(StringRef name, boolean isScript, @NotNull String[] annotations, @NotNull String[] declarationStrings) { super(null); myName = name; this.isScript = isScript; myAnnotations = annotations; + myDeclarationStrings = declarationStrings; } @NotNull @@ -65,7 +79,32 @@ public class GrFileStub extends PsiFileStubImpl { return isScript; } + @NotNull public String[] getAnnotations() { return myAnnotations; } + + @NotNull + public String[] getDeclarationStrings() { + return myDeclarationStrings; + } + + @NotNull + public GrVariableDeclaration[] getAnnotatedScriptDeclarations() { + String[] declarationStrings = getDeclarationStrings(); + if (declarationStrings.length == 0) return GrVariableDeclaration.EMPTY_ARRAY; + + GrVariableDeclaration[] declarations = SoftReference.dereference(myDeclarations); + if (declarations == null) { + GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(getProject()); + GroovyFile psi = getPsi(); + declarations = ContainerUtil.map( + declarationStrings, + declarationString -> factory.createVariableDeclarationFromText(declarationString, psi), + GrVariableDeclaration.EMPTY_ARRAY + ); + myDeclarations = new SoftReference<>(declarations); + } + return declarations; + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java index ff40490b5814..fec05d8d0d31 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java @@ -23,6 +23,7 @@ import com.intellij.psi.StubBuilder; import com.intellij.psi.stubs.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IStubFileElementType; +import com.intellij.util.ArrayUtil; import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; @@ -40,7 +41,7 @@ import java.io.IOException; * @author ilyas */ public class GrStubFileElementType extends IStubFileElementType { - public static final int STUB_VERSION = 32; + public static final int STUB_VERSION = 33; public GrStubFileElementType(Language language) { super(language); @@ -99,6 +100,9 @@ public class GrStubFileElementType extends IStubFileElementType { dataStream.writeName(stub.getName().toString()); dataStream.writeBoolean(stub.isScript()); GrStubUtils.writeStringArray(dataStream, stub.getAnnotations()); + if (stub.isScript()) { + GrStubUtils.writeStringArray(dataStream, stub.getDeclarationStrings()); + } } @NotNull @@ -106,7 +110,15 @@ public class GrStubFileElementType extends IStubFileElementType { public GrFileStub deserialize(@NotNull final StubInputStream dataStream, final StubElement parentStub) throws IOException { StringRef name = dataStream.readName(); boolean isScript = dataStream.readBoolean(); - return new GrFileStub(name, isScript, GrStubUtils.readStringArray(dataStream)); + String[] annotations = GrStubUtils.readStringArray(dataStream); + String[] declarationStrings; + if (isScript) { + declarationStrings = GrStubUtils.readStringArray(dataStream); + } + else { + declarationStrings = ArrayUtil.EMPTY_STRING_ARRAY; + } + return new GrFileStub(name, isScript, annotations, declarationStrings); } @Override