[groovy] store annotated script variable declarations in file stub

This commit is contained in:
Daniil Ovchinnikov
2016-10-31 23:05:56 +03:00
parent 59f2fa54e9
commit 27585f481c
8 changed files with 113 additions and 8 deletions
@@ -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();
}
@@ -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);
@@ -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<GrVariableDeclaration> ARRAY_FACTORY = count -> new GrVariableDeclaration[count];
@Nullable
@@ -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()){
@@ -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) {
@@ -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<GrVariableDeclaration> 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);
}
}
@@ -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<GroovyFile> {
private final String[] myAnnotations;
private final @NotNull String[] myAnnotations;
private final StringRef myName;
private final boolean isScript;
private final @NotNull String[] myDeclarationStrings;
private SoftReference<GrVariableDeclaration[]> myDeclarations;
public GrFileStub(GroovyFile file) {
super(file);
@@ -39,16 +46,23 @@ public class GrFileStub extends PsiFileStubImpl<GroovyFile> {
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<GroovyFile> {
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;
}
}
@@ -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<GrFileStub> {
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<GrFileStub> {
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<GrFileStub> {
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