@Nullable static PsiAnnotation findKotlinSignatureAnnotation(@NotNull PsiElement element) { if (!(element instanceof PsiModifierListOwner)) return null; PsiModifierListOwner annotationOwner = getAnnotationOwner(element); PsiAnnotation ownAnnotation = PsiBasedExternalAnnotationResolver.findOwnAnnotation(annotationOwner, KOTLIN_SIGNATURE); PsiAnnotation annotation = ownAnnotation != null ? ownAnnotation : PsiBasedExternalAnnotationResolver.findExternalAnnotation( annotationOwner, KOTLIN_SIGNATURE.getFqName()); if (annotation == null) return null; if (annotation.getParameterList().getAttributes().length == 0) return null; return annotation; }
class KotlinSignatureUtil { static final String KOTLIN_SIGNATURE_ANNOTATION = KOTLIN_SIGNATURE.getFqName().asString(); private KotlinSignatureUtil() {} @NotNull static PsiModifierListOwner getAnnotationOwner(@NotNull PsiElement element) { PsiModifierListOwner annotationOwner = element.getOriginalElement() instanceof PsiModifierListOwner ? (PsiModifierListOwner) element.getOriginalElement() : (PsiModifierListOwner) element; if (!annotationOwner.isPhysical()) { // this is fake PsiFile which is mirror for ClsFile without sources ASTNode node = SourceTreeToPsiMap.psiElementToTree(element); if (node != null) { PsiCompiledElement compiledElement = node.getUserData(ClsElementImpl.COMPILED_ELEMENT); if (compiledElement instanceof PsiModifierListOwner) { return (PsiModifierListOwner) compiledElement; } } } return annotationOwner; } @NotNull static String getKotlinSignature(@NotNull PsiAnnotation kotlinSignatureAnnotation) { PsiNameValuePair pair = kotlinSignatureAnnotation.getParameterList().getAttributes()[0]; PsiAnnotationMemberValue value = pair.getValue(); if (value == null) { return "null"; } else if (value instanceof PsiLiteralExpression) { Object valueObject = ((PsiLiteralExpression) value).getValue(); return valueObject == null ? "null" : StringUtil.unescapeStringCharacters(valueObject.toString()); } else { return value.getText(); } } @NotNull static PsiNameValuePair[] signatureToNameValuePairs( @NotNull Project project, @NotNull String signature) { return JavaPsiFacade.getElementFactory(project) .createAnnotationFromText( "@" + KOTLIN_SIGNATURE_ANNOTATION + "(value=\"" + StringUtil.escapeStringCharacters(signature) + "\")", null) .getParameterList() .getAttributes(); } @Nullable static PsiAnnotation findKotlinSignatureAnnotation(@NotNull PsiElement element) { if (!(element instanceof PsiModifierListOwner)) return null; PsiModifierListOwner annotationOwner = getAnnotationOwner(element); PsiAnnotation ownAnnotation = PsiBasedExternalAnnotationResolver.findOwnAnnotation(annotationOwner, KOTLIN_SIGNATURE); PsiAnnotation annotation = ownAnnotation != null ? ownAnnotation : PsiBasedExternalAnnotationResolver.findExternalAnnotation( annotationOwner, KOTLIN_SIGNATURE.getFqName()); if (annotation == null) return null; if (annotation.getParameterList().getAttributes().length == 0) return null; return annotation; } static void refreshMarkers(@NotNull Project project) { DaemonCodeAnalyzer.getInstance(project).restart(); } static boolean isAnnotationEditable(@NotNull PsiElement element) { PsiModifierListOwner annotationOwner = getAnnotationOwner(element); PsiAnnotation annotation = findKotlinSignatureAnnotation(element); assert annotation != null; if (annotation.getContainingFile() == annotationOwner.getContainingFile()) { return annotation.isWritable(); } else { ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(element.getProject()); return annotationsManager.isExternalAnnotationWritable( annotationOwner, KOTLIN_SIGNATURE_ANNOTATION); } } }