@Override public void annotateExternally( @NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQName, @NotNull final PsiFile fromFile, final PsiNameValuePair[] value) { final Project project = myPsiManager.getProject(); final PsiFile containingFile = listOwner.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { return; } final String packageName = ((PsiJavaFile) containingFile).getPackageName(); final VirtualFile virtualFile = containingFile.getVirtualFile(); LOG.assertTrue(virtualFile != null); final List<OrderEntry> entries = ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(virtualFile); if (entries.isEmpty()) { return; } for (final OrderEntry entry : entries) { if (entry instanceof ModuleOrderEntry) continue; VirtualFile[] virtualFiles = AnnotationOrderRootType.getFiles(entry); virtualFiles = filterByReadOnliness(virtualFiles); if (virtualFiles.length > 0) { chooseRootAndAnnotateExternally( listOwner, annotationFQName, fromFile, project, packageName, virtualFile, virtualFiles, value); } else { if (ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isHeadlessEnvironment()) { return; } SwingUtilities.invokeLater( new Runnable() { @Override public void run() { setupRootAndAnnotateExternally( entry, project, listOwner, annotationFQName, fromFile, packageName, virtualFile, value); } }); } break; } }
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); } }
@Override public void invoke( @NotNull Project project, @NotNull PsiFile file, @Nullable("is null when called from inspection") Editor editor, @NotNull PsiElement startElement, @NotNull PsiElement endElement) { final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner) startElement; final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project); final PsiModifierList modifierList = myModifierListOwner.getModifierList(); LOG.assertTrue(modifierList != null); if (modifierList.findAnnotation(myAnnotation) != null) return; final ExternalAnnotationsManager.AnnotationPlace annotationAnnotationPlace = annotationsManager.chooseAnnotationsPlace(myModifierListOwner); if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NOWHERE) return; if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.EXTERNAL) { for (String fqn : myAnnotationsToRemove) { annotationsManager.deannotate(myModifierListOwner, fqn); } annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs); } else { final PsiFile containingFile = myModifierListOwner.getContainingFile(); if (!CodeInsightUtilBase.preparePsiElementForWrite(containingFile)) return; for (String fqn : myAnnotationsToRemove) { PsiAnnotation annotation = AnnotationUtil.findAnnotation(myModifierListOwner, fqn); if (annotation != null) { annotation.delete(); } } PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation); for (PsiNameValuePair pair : myPairs) { inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue()); } JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted); if (containingFile != file) { UndoUtil.markPsiFileForUndo(file); } } }
@Override @Nullable public List<PsiFile> findExternalAnnotationsFiles(@NotNull PsiModifierListOwner listOwner) { final PsiFile containingFile = listOwner.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { return null; } final PsiJavaFile javaFile = (PsiJavaFile) containingFile; final String packageName = javaFile.getPackageName(); final VirtualFile virtualFile = containingFile.getVirtualFile(); if (virtualFile == null) return null; final List<PsiFile> files = myExternalAnnotations.get(virtualFile); if (files == NULL_LIST) return null; if (files != null) { boolean allValid = true; for (PsiFile file : files) { allValid &= file.isValid(); } if (allValid) { return files; } } if (virtualFile == null) { return null; } Set<PsiFile> possibleAnnotationsXmls = new THashSet<PsiFile>(); for (VirtualFile root : getExternalAnnotationsRoots(virtualFile)) { final VirtualFile ext = root.findFileByRelativePath(packageName.replace('.', '/') + "/" + ANNOTATIONS_XML); if (ext == null) continue; final PsiFile psiFile = myPsiManager.findFile(ext); if (psiFile == null) continue; possibleAnnotationsXmls.add(psiFile); } List<PsiFile> result; if (possibleAnnotationsXmls.isEmpty()) { myExternalAnnotations.put(virtualFile, NULL_LIST); result = null; } else { result = new SmartList<PsiFile>(possibleAnnotationsXmls); // sorting by writability: writable go first Collections.sort( result, new Comparator<PsiFile>() { @Override public int compare(PsiFile f1, PsiFile f2) { boolean w1 = f1.isWritable(); boolean w2 = f2.isWritable(); if (w1 == w2) { return 0; } return w1 ? -1 : 1; } }); myExternalAnnotations.put(virtualFile, result); } return result; }