[groovy] support @BaseScript on package definition and import statements (IDEA-135602)

GitOrigin-RevId: 00ae8b515abd00032cef680fa012faaecfcbb138
This commit is contained in:
Pavel Novichenko
2019-07-02 06:52:16 +03:00
committed by intellij-monorepo-bot
parent 91f264fe2c
commit bedad949e5
3 changed files with 105 additions and 33 deletions
@@ -1,32 +1,19 @@
/*
* Copyright 2000-2014 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.annotator.checkers;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
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;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
public class BaseScriptAnnotationChecker extends CustomAnnotationChecker {
@@ -50,8 +37,31 @@ public class BaseScriptAnnotationChecker extends CustomAnnotationChecker {
return true;
}
}
else if (pparent instanceof GrPackageDefinition || pparent instanceof GrImportStatement) {
PsiClass clazz = GrAnnotationUtil.inferClassAttribute(annotation, "value");
if (!InheritanceUtil.isInheritor(clazz, GroovyCommonClassNames.GROOVY_LANG_SCRIPT)) {
String typeText = getTypeText(clazz);
holder.createErrorAnnotation(annotation, GroovyBundle.message("declared.type.0.have.to.extend.script", typeText));
}
}
}
return false;
}
@NotNull
public String getTypeText(@Nullable PsiClass clazz) {
if (clazz == null) {
return CommonClassNames.JAVA_LANG_OBJECT;
}
String fqn = clazz.getQualifiedName();
if (fqn != null) {
return fqn;
}
String name = clazz.getName();
if (name != null) {
return name;
}
return CommonClassNames.JAVA_LANG_OBJECT;
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.codeInsight.AnnotationUtil;
@@ -67,7 +67,7 @@ public class GrAnnotationUtil {
}
@Nullable
private static PsiClass getPsiClass(@Nullable PsiAnnotationMemberValue targetValue) {
public static PsiClass getPsiClass(@Nullable PsiAnnotationMemberValue targetValue) {
if (targetValue instanceof PsiClassObjectAccessExpression) {
PsiType type = ((PsiClassObjectAccessExpression)targetValue).getOperand().getType();
if (type instanceof PsiClassType) {
@@ -1,10 +1,7 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.transformations.impl;
import com.intellij.psi.PsiArrayType;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
@@ -13,8 +10,12 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyLanguage;
import org.jetbrains.plugins.groovy.dsl.GroovyDslFileIndex;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
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;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
@@ -22,6 +23,8 @@ import org.jetbrains.plugins.groovy.transformations.AstTransformationSupport;
import org.jetbrains.plugins.groovy.transformations.TransformationContext;
import static com.intellij.psi.impl.cache.impl.id.IdIndex.hasIdentifierInFile;
import static org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtilKt.findDeclaredDetachedValue;
import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_TRANSFORM_BASE_SCRIPT;
public class BaseScriptTransformationSupport implements AstTransformationSupport {
@@ -47,7 +50,9 @@ public class BaseScriptTransformationSupport implements AstTransformationSupport
@NotNull
private static PsiClassType getBaseClassType(@NotNull GroovyScriptClass scriptClass) {
PsiClassType type = getSuperClassTypeFromBaseScriptAnnotatedVariable(scriptClass);
PsiClassType type = CachedValuesManager.getCachedValue(scriptClass, () -> CachedValueProvider.Result.create(
getSuperClassTypeFromBaseScriptAnnotation(scriptClass), scriptClass.getContainingFile()
));
if (type != null) return type;
final PsiClassType superClassFromDSL = GroovyDslFileIndex.processScriptSuperClasses(scriptClass.getContainingFile());
@@ -57,13 +62,70 @@ public class BaseScriptTransformationSupport implements AstTransformationSupport
}
@Nullable
private static PsiClassType getSuperClassTypeFromBaseScriptAnnotatedVariable(GroovyScriptClass scriptClass) {
return CachedValuesManager.getCachedValue(scriptClass, () -> CachedValueProvider.Result.create(
doGetSuperClassType(scriptClass), scriptClass.getContainingFile()
));
private static PsiClassType getSuperClassTypeFromBaseScriptAnnotation(@NotNull GroovyScriptClass scriptClass) {
//Groovy BaseScriptASTTransformation works exactly with this priorities
PsiClassType fromVariable = getSuperClassTypeFromBaseScriptAnnotatedVariable(scriptClass);
if (fromVariable != null) {
return fromVariable;
}
PsiClassType fromImport = getSuperClassTypeFromBaseScriptAnnotatedImportDefinition(scriptClass);
if (fromImport != null) {
return fromImport;
}
return getSuperClassTypeFromBaseScriptAnnotatedPackageDefinition(scriptClass);
}
private static PsiClassType doGetSuperClassType(GroovyScriptClass scriptClass) {
@Nullable
private static PsiClassType getSuperClassTypeFromBaseScriptAnnotatedImportDefinition(@NotNull GroovyScriptClass scriptClass) {
GrImportStatement[] importStatements = scriptClass.getContainingFile().getImportStatements();
for (GrImportStatement importStatement : importStatements) {
GrModifierList annotations = importStatement.getAnnotationList();
PsiAnnotation baseScriptAnnotation = annotations.findAnnotation(GROOVY_TRANSFORM_BASE_SCRIPT);
if (baseScriptAnnotation == null) {
continue;
}
PsiClassType superClassType = getSuperClassTypeFromAnnotationValue(scriptClass, baseScriptAnnotation);
if (superClassType != null) {
return superClassType;
}
}
return null;
}
@Nullable
private static PsiClassType getSuperClassTypeFromBaseScriptAnnotatedPackageDefinition(@NotNull GroovyScriptClass scriptClass) {
GrPackageDefinition packageDefinition = scriptClass.getContainingFile().getPackageDefinition();
if (packageDefinition == null) {
return null;
}
PsiModifierList modifierList = packageDefinition.getModifierList();
if (modifierList == null) {
return null;
}
PsiAnnotation baseScriptAnnotation = modifierList.findAnnotation(GROOVY_TRANSFORM_BASE_SCRIPT);
if (baseScriptAnnotation == null) {
return null;
}
return getSuperClassTypeFromAnnotationValue(scriptClass, baseScriptAnnotation);
}
@Nullable
private static PsiClassType getSuperClassTypeFromAnnotationValue(GroovyScriptClass scriptClass, PsiAnnotation baseScriptAnnotation) {
PsiClass clazz = GrAnnotationUtil.getPsiClass(findDeclaredDetachedValue(baseScriptAnnotation, "value"));
if (clazz != null) {
String className = clazz.getQualifiedName();
if (className == null) clazz.getName();
if (className != null) {
return TypesUtil.createTypeByFQClassName(className, scriptClass);
}
}
return null;
}
@Nullable
private static PsiClassType getSuperClassTypeFromBaseScriptAnnotatedVariable(GroovyScriptClass scriptClass) {
GrVariableDeclaration declaration = findDeclaration(scriptClass.getContainingFile());
if (declaration != null) {
GrTypeElement typeElement = declaration.getTypeElementGroovy();
@@ -83,7 +145,7 @@ public class BaseScriptTransformationSupport implements AstTransformationSupport
return null;
}
for (GrVariableDeclaration declaration : file.getScriptDeclarations(false)) {
if (declaration.getModifierList().hasAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_BASE_SCRIPT)) {
if (declaration.getModifierList().hasAnnotation(GROOVY_TRANSFORM_BASE_SCRIPT)) {
return declaration;
}
}