IntentionAction (final GrReferenceElement refElement, GrCreateClassKind type) { return new CreateClassActionBase(type, refElement) { @Override protected void processIntention(@NotNull PsiElement element, @NotNull Project project, Editor editor) throws IncorrectOperationException { final PsiFile file = element.getContainingFile(); if (!(file instanceof GroovyFileBase groovyFile)) return; PsiElement qualifier = myRefElement.getQualifier(); if (qualifier == null || qualifier instanceof GrReferenceElement && ((GrReferenceElement<?>)qualifier).resolve() instanceof PsiPackage) { createTopLevelClass(project, groovyFile); } else { createInnerClass(project, editor, qualifier); } } private void createInnerClass(Project project, final Editor editor, PsiElement qualifier) { PsiElement resolved = resolveQualifier(qualifier); if (!(resolved instanceof PsiClass)) return; JVMElementFactory factory = JVMElementFactories.getFactory(resolved.getLanguage(), project); if (factory == null) return; String name = myRefElement.getReferenceName(); PsiClass template = createTemplate(factory, name); if (template == null) { ApplicationManager.getApplication().invokeLater(() -> { if (editor != null && editor.getComponent().isDisplayable()) { HintManager.getInstance().showErrorHint(editor, GroovyBundle.message("cannot.create.class")); } }); return; } if (!FileModificationService.getInstance().preparePsiElementForWrite(resolved)) return; WriteAction.run(() -> { PsiClass added = (PsiClass)resolved.add(template); PsiModifierList modifierList = added.getModifierList(); if (modifierList != null) { modifierList.setModifierProperty(PsiModifier.STATIC, true); } IntentionUtils.positionCursor(project, added.getContainingFile(), added); }); } @Nullable private static PsiElement resolveQualifier(@NotNull PsiElement qualifier) { if (qualifier instanceof GrCodeReferenceElement) { return ((GrCodeReferenceElement)qualifier).resolve(); } else if (qualifier instanceof GrExpression) { PsiType type = ((GrExpression)qualifier).getType(); if (type instanceof PsiClassType) { return ((PsiClassType)type).resolve(); } else if (qualifier instanceof GrReferenceExpression) { final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); if (resolved instanceof PsiClass || resolved instanceof PsiPackage) { return resolved; } } } return null; } @Nullable private PsiClass createTemplate(JVMElementFactory factory, String name) { return switch (getType()) { case ENUM -> factory.createEnum(name); case TRAIT -> { if (factory instanceof GroovyPsiElementFactory groovyFactory) { yield groovyFactory.createTrait(name); } yield null; } case CLASS -> factory.createClass(name); case INTERFACE -> factory.createInterface(name); case ANNOTATION -> factory.createAnnotationType(name); case RECORD -> { if (factory instanceof GroovyPsiElementFactory groovyFactory) { yield groovyFactory.createRecord(name); } yield null; } }; } private void createTopLevelClass(@NotNull Project project, @NotNull GroovyFileBase file) { final String pack = getPackage(file); final PsiManager manager = PsiManager.getInstance(project); final String name = myRefElement.getReferenceName(); assert name != null; final Module module = ModuleUtilCore.findModuleForPsiElement(file); PsiDirectory targetDirectory = getTargetDirectory(project, pack, name, module, getText()); if (targetDirectory == null) return; String templateName = getTemplateName(getType()); final PsiClass targetClass = createClassByType(targetDirectory, name, manager, myRefElement, templateName, true); if (targetClass == null) return; bindRef(targetClass, myRefElement); IntentionUtils.positionCursor(project, targetClass.getContainingFile(), targetClass); } @NotNull private String getPackage(@NotNull PsiClassOwner file) { final PsiElement qualifier = myRefElement.getQualifier(); if (qualifier instanceof GrReferenceElement) { final PsiElement resolved = ((GrReferenceElement<?>)qualifier).resolve(); if (resolved instanceof PsiPackage) { return ((PsiPackage)resolved).getQualifiedName(); } } return file instanceof GroovyFile ? file.getPackageName() : ""; } @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { if (!super.isAvailable(project, editor, file)) return false; final PsiElement qualifier = myRefElement.getQualifier(); if (qualifier != null && resolveQualifier(qualifier) == null) { return false; } return true; } }; }