From 7370107616ed6cba62f14f457d6b26fdaa3f3b19 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Tue, 31 Jul 2012 20:15:52 +0400 Subject: [PATCH] Optimized reading external annotations: now they when annotations file is accessed, it's parsed data is stored in cache. --- .../CoreAnnotationsProvider.java | 113 +++++++++++------- 1 file changed, 69 insertions(+), 44 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/extAnnotations/CoreAnnotationsProvider.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/extAnnotations/CoreAnnotationsProvider.java index e9350f8e272..999138227fa 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/extAnnotations/CoreAnnotationsProvider.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/extAnnotations/CoreAnnotationsProvider.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.resolve.java.extAnnotations; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; @@ -28,16 +27,15 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.containers.ConcurrentWeakHashMap; import com.intellij.util.containers.ConcurrentWeakValueHashMap; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.BufferedInputStream; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.util.*; import java.util.concurrent.ConcurrentMap; @@ -49,6 +47,8 @@ import java.util.concurrent.ConcurrentMap; */ @Deprecated public class CoreAnnotationsProvider extends ExternalAnnotationsProvider { + static int loadDocumentCount = 0; + static { // This is an ugly workaround for JDOM 1.1 used from application started from Ant 1.8 without forking System.setProperty("javax.xml.parsers.SAXParserFactory", "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"); @@ -135,66 +135,81 @@ public class CoreAnnotationsProvider extends ExternalAnnotationsProvider { externalAnnotationsRoots.add(externalAnnotationsRoot); } - private Map doCollect(@NotNull PsiModifierListOwner listOwner) { - final List files = findExternalAnnotationsFiles(listOwner); - if (files == null) { - return Collections.emptyMap(); + private Map> annotationsFileToData = new HashMap>(); + private Map annotationsFileToModificationStamp = new HashMap(); + @NotNull + private MultiMap getDataFromFile(@NotNull PsiFile file) { + if (annotationsFileToData.containsKey(file) && file.getModificationStamp() == annotationsFileToModificationStamp.get(file)) { + return annotationsFileToData.get(file); } - final Map result = new HashMap(); - for (PsiFile file : files) { - if (!file.isValid()) continue; - final Document document; + else { + MultiMap data = new MultiMap(); + annotationsFileToData.put(file, data); + annotationsFileToModificationStamp.put(file, file.getModificationStamp()); + + Document document; try { - // CoreLocalVirtualFile.getInputStream() fails with AssertionError - VirtualFile virtualFile = file.getVirtualFile(); - InputStream stream = "CoreLocalVirtualFile".equals(virtualFile.getClass().getSimpleName()) - ? new BufferedInputStream(new FileInputStream(virtualFile.getPath())) - : virtualFile.getInputStream(); - document = JDOMUtil.loadDocument(escapeAttributes(StreamUtil.readText(stream))); + //noinspection ConstantConditions + System.out.println("loadDocument count = " + (loadDocumentCount++)); + document = JDOMUtil.loadDocument(escapeAttributes(StreamUtil.readText(file.getVirtualFile().getInputStream()))); } catch (IOException e) { - LOG.error(e); - continue; + return data; } catch (JDOMException e) { LOG.error(e); - continue; + return data; } - if (document == null) continue; - final Element rootElement = document.getRootElement(); - if (rootElement == null) continue; - final String externalName = getExternalName(listOwner, false); - final String oldExternalName = getNormalizedExternalName(listOwner); + Element rootElement = document.getRootElement(); + if (rootElement == null) return data; + //noinspection unchecked - for (final Element element : (List) rootElement.getChildren()) { - final String className = element.getAttributeValue("name"); - if (!Comparing.strEqual(className, externalName) && !Comparing.strEqual(className, oldExternalName)) { - continue; - } + for (Element element : (List) rootElement.getChildren()) { + String ownerName = element.getAttributeValue("name"); + if (ownerName == null) continue; //noinspection unchecked for (Element annotationElement : (List) element.getChildren()) { - final String annotationFQN = annotationElement.getAttributeValue("name"); - final StringBuilder buf = new StringBuilder(); + String annotationFQN = annotationElement.getAttributeValue("name"); + StringBuilder buf = new StringBuilder(); //noinspection unchecked for (Element annotationParameter : (List) annotationElement.getChildren()) { buf.append(","); - final String nameValue = annotationParameter.getAttributeValue("name"); + String nameValue = annotationParameter.getAttributeValue("name"); if (nameValue != null) { buf.append(nameValue).append("="); } buf.append(annotationParameter.getAttributeValue("val")); } - final String annotationText = - "@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : ""); - try { - result.put(annotationFQN, - JavaPsiFacade.getInstance(listOwner.getProject()).getElementFactory().createAnnotationFromText( - annotationText, null)); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } + String annotationText = "@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : ""); + data.putValue(ownerName, new AnnotationData(annotationFQN, annotationText)); + } + } + + return data; + } + } + + private Map doCollect(@NotNull PsiModifierListOwner listOwner) { + final List files = findExternalAnnotationsFiles(listOwner); + if (files == null) { + return Collections.emptyMap(); + } + Map result = new HashMap(); + String externalName = getExternalName(listOwner, false); + String oldExternalName = getNormalizedExternalName(listOwner); + + for (PsiFile file : files) { + if (!file.isValid()) continue; + MultiMap fileData = getDataFromFile(file); + for (AnnotationData annotationData : ContainerUtil.concat(fileData.get(externalName), fileData.get(oldExternalName))) { + try { + result.put(annotationData.annotationClassFqName, + JavaPsiFacade.getInstance(listOwner.getProject()).getElementFactory().createAnnotationFromText( + annotationData.annotationText, null)); + } + catch (IncorrectOperationException e) { + LOG.error(e); } } } @@ -291,4 +306,14 @@ public class CoreAnnotationsProvider extends ExternalAnnotationsProvider { } return sb.toString(); } + + private static class AnnotationData { + public String annotationClassFqName; + public String annotationText; + + private AnnotationData(String annotationClassFqName, String annotationText) { + this.annotationClassFqName = annotationClassFqName; + this.annotationText = annotationText; + } + } }