This commit is contained in:
Alexey Kudravtsev
2012-01-16 18:32:15 +04:00
parent 3fac1f091f
commit accecdb788
10 changed files with 144 additions and 78 deletions
@@ -118,10 +118,10 @@ public class JavaConcatenationInjectorManager implements ModificationTracker {
JavaConcatenationInjectorManager concatenationInjectorManager = getInstance(project);
for (ConcatenationAwareInjector concatenationInjector : concatenationInjectorManager.myConcatenationInjectors) {
concatenationInjector.getLanguagesToInject(registrar, operands);
if (registrar.result != null) break;
if (registrar.getResult() != null) break;
}
if (registrar.result == null) {
if (registrar.getResult() == null) {
registrar = null;
}
return registrar;
@@ -155,31 +155,26 @@ public class JavaConcatenationInjectorManager implements ModificationTracker {
}
else {
data = anchor.getUserData(INJECTED_PSI_IN_CONCATENATION);
if (data == null) {
result = doCompute(context, project, anchor, operands);
if (result != null) {
}
}
else {
result = data.getValue(context);
}
}
if (result != null && result.result != null) {
for (Pair<Place, PsiFile> p : result.result) {
if (result != null && result.getResult() != null) {
for (Pair<Place, PsiFile> p : result.getResult()) {
((MultiHostRegistrarImpl)registrar).addToResults(p.first, p.second);
}
if (data == null) {
CachedValueProvider.Result<MultiHostRegistrarImpl> cachedResult =
CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT, getInstance(project));
ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> cachedValue =
CachedValuesManager.getManager(context.getProject())
.createParameterizedCachedValue(CONCATENATION_PSI_CACHED_VALUE_PROVIDER, false);
((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>)cachedValue).setValue(cachedResult);
data = CachedValuesManager.getManager(project).createParameterizedCachedValue(CONCATENATION_PSI_CACHED_VALUE_PROVIDER, false);
((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>)data).setValue(cachedResult);
anchor.putUserData(INJECTED_PSI_IN_CONCATENATION, cachedValue);
anchor.putUserData(INJECTED_PSI_IN_CONCATENATION, data);
if (anchor.getUserData(NO_CONCAT_INJECTION_TIMESTAMP) != null) {
anchor.putUserData(NO_CONCAT_INJECTION_TIMESTAMP, null);
}
@@ -197,8 +192,9 @@ public class JavaConcatenationInjectorManager implements ModificationTracker {
@Override
@NotNull
public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
return Arrays.asList(PsiLiteralExpression.class);
return LITERALS;
}
private static final List<Class<PsiLiteralExpression>> LITERALS = Arrays.asList(PsiLiteralExpression.class);
}
private final List<ConcatenationAwareInjector> myConcatenationInjectors = ContainerUtil.createEmptyCOWList();
@@ -56,13 +56,14 @@ public interface PsiLanguageInjectionHost extends PsiElement {
public final String prefix;
public final String suffix;
public Shred(@NotNull PsiLanguageInjectionHost host, @NotNull RangeMarker relevantRangeInHost, @NotNull String prefix, @NotNull String suffix, @NotNull TextRange range) {
public Shred(@NotNull PsiLanguageInjectionHost host, @NotNull final RangeMarker relevantRangeInHost, @NotNull String prefix, @NotNull String suffix, @NotNull TextRange range) {
this.host = host;
this.relevantRangeInHost = relevantRangeInHost;
this.prefix = prefix;
this.suffix = suffix;
this.range = range;
assert isValid();
assert relevantRangeInHost.isValid();
}
public RangeMarker getHostRangeMarker() {
@@ -71,8 +72,8 @@ public interface PsiLanguageInjectionHost extends PsiElement {
public TextRange getRangeInsideHost() {
TextRange hostTextRange = host.getTextRange();
ProperTextRange textRange = new ProperTextRange(relevantRangeInHost.getStartOffset(), relevantRangeInHost.getEndOffset());
textRange = textRange.intersection(hostTextRange);
ProperTextRange textRange = relevantRangeInHost.isValid() ? new ProperTextRange(relevantRangeInHost.getStartOffset(), relevantRangeInHost.getEndOffset()) : null;
textRange = textRange == null ? null : textRange.intersection(hostTextRange);
if (textRange == null) return new ProperTextRange(0, hostTextRange.getLength());
return textRange.shiftRight(-hostTextRange.getStartOffset());
}
@@ -87,5 +88,24 @@ public interface PsiLanguageInjectionHost extends PsiElement {
public boolean isValid() {
return relevantRangeInHost.isValid() && host.isValid();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shred shred = (Shred)o;
return host.equals(shred.host) &&
prefix.equals(shred.prefix) &&
suffix.equals(shred.suffix) &&
range.equals(shred.range) &&
TextRange.create(relevantRangeInHost).equals(TextRange.create(shred.relevantRangeInHost));
}
@Override
public int hashCode() {
return range.hashCode();
}
}
}
@@ -79,10 +79,10 @@ public abstract class PsiCachedValue<T> extends CachedValueBase<T> {
if (dependency == PsiModificationTracker.MODIFICATION_COUNT) {
return myManager.getModificationTracker().getModificationCount();
}
else if (dependency == PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) {
if (dependency == PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) {
return myManager.getModificationTracker().getOutOfCodeBlockModificationCount();
}
else if (dependency == PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT) {
if (dependency == PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT) {
return myManager.getModificationTracker().getJavaStructureModificationCount();
}
@@ -345,6 +345,9 @@ public class HighlightInfo implements Segment {
if (quickFixActionRanges != null) {
s+= "; quickFixes: "+quickFixActionRanges;
}
if (gutterIconRenderer != null) {
s += "; gutter: " + gutterIconRenderer;
}
return s;
}
@@ -58,7 +58,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
private CachedText myCachedText = null;
public DocumentWindowImpl(@NotNull DocumentEx delegate, boolean oneLine, Place shreds) {
public DocumentWindowImpl(@NotNull DocumentEx delegate, boolean oneLine, @NotNull Place shreds) {
myDelegate = delegate;
myOneLine = oneLine;
synchronized (myLock) {
@@ -889,13 +889,12 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
public void setShreds(@NotNull Place shreds) {
synchronized (myLock) {
if (myShreds != shreds) {
myShreds.dispose();
myShreds = shreds;
}
myShreds.dispose();
myShreds = shreds;
}
}
@NotNull
public Place getShreds() {
synchronized (myLock) {
return myShreds;
@@ -114,13 +114,33 @@ public class InjectedFileViewProvider extends SingleRootFileViewProvider impleme
return file;
}
void setShreds(@NotNull Place shreds) {
// returns true if shreds were set, false if old ones were reused
boolean setShreds(@NotNull Place newShreds, @NotNull Project project) {
synchronized (myLock) {
myProject = shreds.get(0).host.getProject();
myDocumentWindow.setShreds(shreds);
myProject = project;
Place oldShreds = myDocumentWindow.getShreds();
// try to reuse shreds, otherwise there are too many range markers disposals/re-creations
if (same(oldShreds, newShreds)) {
return false;
}
else {
myDocumentWindow.setShreds(newShreds);
return true;
}
}
}
private static boolean same(Place oldShreds, Place newShreds) {
if (oldShreds == newShreds) return true;
if (oldShreds.size() != newShreds.size()) return false;
for (int i = 0; i < oldShreds.size(); i++) {
PsiLanguageInjectionHost.Shred oldShred = oldShreds.get(i);
PsiLanguageInjectionHost.Shred newShred = newShreds.get(i);
if (!oldShred.equals(newShred)) return false;
}
return true;
}
boolean isValid() {
return getShreds().isValid();
}
@@ -91,7 +91,12 @@ public class InjectedLanguageUtil {
}
}
});
return result.isEmpty() ? null : result;
if (result.isEmpty()) {
return null;
}
else {
return result;
}
}
public static List<Trinity<IElementType, PsiLanguageInjectionHost, TextRange>> getHighlightTokens(PsiFile file) {
@@ -134,8 +139,10 @@ public class InjectedLanguageUtil {
}
MultiHostRegistrarImpl registrar = probeElementsUp(host, containingFile, probeUp);
if (registrar == null) return;
List<Pair<Place, PsiFile>> places = registrar.result;
if (registrar == null) {
return;
}
List<Pair<Place, PsiFile>> places = registrar.getResult();
for (Pair<Place, PsiFile> pair : places) {
PsiFile injectedPsi = pair.second;
visitor.visit(injectedPsi, pair.first);
@@ -202,7 +209,9 @@ public class InjectedLanguageUtil {
PsiManager psiManager = hostPsiFile.getManager();
final Project project = psiManager.getProject();
InjectedLanguageManagerImpl injectedManager = InjectedLanguageManagerImpl.getInstanceImpl(project);
if (injectedManager == null) return null; //for tests
if (injectedManager == null) {
return null; //for tests
}
MultiHostRegistrarImpl registrar = null;
PsiElement current = element;
nextParent:
@@ -216,10 +225,12 @@ public class InjectedLanguageUtil {
else {
registrar = data.getValue(current);
}
log(current, (registrar == null ? "!": "")+" computed result="+registrar);
current = current.getParent(); // cache no injection for current
if (registrar != null) {
List<Pair<Place, PsiFile>> places = registrar.result;
List<Pair<Place, PsiFile>> places = registrar.getResult();
// check that injections found intersect with queried element
TextRange elementRange = element.getTextRange();
for (Pair<Place, PsiFile> pair : places) {
@@ -242,31 +253,28 @@ public class InjectedLanguageUtil {
ProgressManager.checkCanceled();
if (registrar == null) {
e.putUserData(INJECTED_PSI, null);
log(e, "Cache .INJECTED_PSI=null");
}
else {
ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> cachedValue =
CachedValuesManager.getManager(project).createParameterizedCachedValue(INJECTED_PSI_PROVIDER, false);
CachedValueProvider.Result<MultiHostRegistrarImpl> result = CachedValueProvider.Result.create(registrar, PsiModificationTracker.MODIFICATION_COUNT, calcDependencies(registrar));
CachedValueProvider.Result<MultiHostRegistrarImpl> result = CachedValueProvider.Result.create(registrar, PsiModificationTracker.MODIFICATION_COUNT, registrar);
((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>)cachedValue).setValue(result);
e.putUserData(INJECTED_PSI, cachedValue);
log(e, "Cache .INJECTED_PSI="+result);
}
}
}
return registrar;
}
private static Object[] calcDependencies(@NotNull MultiHostRegistrarImpl registrar) {
List<Pair<Place, PsiFile>> result = registrar.getResult();
Object[] deps = new Object[result.size()];
for (int i = 0; i < result.size(); i++) {
Pair<Place, PsiFile> pair = result.get(i);
PsiFile injectedFile = pair.second;
Document injDocument = injectedFile.getViewProvider().getDocument();
deps[i] = injDocument;
}
return deps;
public static void log(PsiElement e, String msg) {
//if (e.getClass().getName().equals("com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl")) {
// System.out.println(e+": "+ msg + " ("+Thread.currentThread()+")");
//}
}
public static PsiElement findInjectedElementNoCommit(@NotNull PsiFile hostFile, final int offset) {
@@ -19,6 +19,7 @@ package com.intellij.psi.impl.source.tree.injected;
import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -28,6 +29,8 @@ import com.intellij.psi.util.ParameterizedCachedValueProvider;
import com.intellij.psi.util.PsiModificationTracker;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author cdr
*/
@@ -50,11 +53,14 @@ class InjectedPsiCachedValueProvider implements ParameterizedCachedValueProvider
}
@Nullable
static MultiHostRegistrarImpl doCompute(final PsiElement element, InjectedLanguageManagerImpl injectedManager, Project project, PsiFile hostPsiFile) {
static MultiHostRegistrarImpl doCompute(final PsiElement element,
InjectedLanguageManagerImpl injectedManager,
Project project,
PsiFile hostPsiFile) {
MyInjProcessor processor = new MyInjProcessor(project, hostPsiFile);
injectedManager.processInPlaceInjectorsFor(element, processor);
MultiHostRegistrarImpl registrar = processor.hostRegistrar;
return registrar == null || registrar.result == null ? null : registrar;
return registrar == null || registrar.getResult() == null ? null : registrar;
}
private static class MyInjProcessor implements InjectedLanguageManagerImpl.InjProcessor {
@@ -73,7 +79,8 @@ class InjectedPsiCachedValueProvider implements ParameterizedCachedValueProvider
hostRegistrar = new MultiHostRegistrarImpl(myProject, myHostPsiFile, element);
}
injector.getLanguagesToInject(hostRegistrar, element);
return hostRegistrar.result == null;
List<Pair<Place,PsiFile>> result = hostRegistrar.getResult();
return result == null;
}
}
}
@@ -66,8 +66,8 @@ import java.util.Map;
/**
* @author cdr
*/
public class MultiHostRegistrarImpl implements MultiHostRegistrar {
List<Pair<Place, PsiFile>> result;
public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationTracker {
private List<Pair<Place, PsiFile>> result;
private Language myLanguage;
private List<LiteralTextEscaper<? extends PsiLanguageInjectionHost>> escapers;
private List<PsiLanguageInjectionHost.Shred> shreds;
@@ -76,24 +76,22 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
private boolean cleared;
private final Project myProject;
private final PsiManager myPsiManager;
private DocumentEx myHostDocument;
private VirtualFile myHostVirtualFile;
private final DocumentEx myHostDocument;
private final VirtualFile myHostVirtualFile;
private final PsiElement myContextElement;
private final PsiFile myHostPsiFile;
MultiHostRegistrarImpl(@NotNull Project project, @NotNull PsiFile hostPsiFile, @NotNull PsiElement contextElement) {
MultiHostRegistrarImpl(@NotNull Project project,
@NotNull PsiFile hostPsiFile,
@NotNull PsiElement contextElement) {
myProject = project;
myContextElement = contextElement;
myHostPsiFile = PsiUtilCore.getTemplateLanguageFile(hostPsiFile);
myPsiManager = myHostPsiFile.getManager();
cleared = true;
}
// null registrar
MultiHostRegistrarImpl() {
myProject = null;
myContextElement = null;
myHostPsiFile = null;
myPsiManager = null;
FileViewProvider viewProvider = myHostPsiFile.getViewProvider();
myHostVirtualFile = viewProvider.getVirtualFile();
myHostDocument = (DocumentEx)viewProvider.getDocument();
}
public List<Pair<Place, PsiFile>> getResult() {
@@ -122,10 +120,6 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
}
myLanguage = language;
FileViewProvider viewProvider = myHostPsiFile.getViewProvider();
myHostVirtualFile = viewProvider.getVirtualFile();
myHostDocument = (DocumentEx)viewProvider.getDocument();
assert myHostDocument != null : myHostPsiFile + "; " + viewProvider;
return this;
}
@@ -267,7 +261,11 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
viewProvider = (InjectedFileViewProvider)psiFile.getViewProvider();
documentWindow = (DocumentWindowImpl)viewProvider.getDocument();
virtualFile = (VirtualFileWindowImpl)viewProvider.getVirtualFile();
cacheEverything(place, documentWindow, viewProvider, psiFile, pointer);
boolean shredsRewritten = cacheEverything(place, documentWindow, viewProvider, psiFile, pointer);
if (!shredsRewritten) {
place.dispose();
place = documentWindow.getShreds();
}
}
assert psiFile.isValid();
@@ -295,11 +293,12 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
}
}
private static void cacheEverything(@NotNull Place place,
@NotNull DocumentWindowImpl documentWindow,
@NotNull InjectedFileViewProvider viewProvider,
@NotNull PsiFile psiFile,
@NotNull SmartPsiElementPointer<PsiLanguageInjectionHost> pointer) {
// returns true if shreds were set, false if old ones were reused
private static boolean cacheEverything(@NotNull Place place,
@NotNull DocumentWindowImpl documentWindow,
@NotNull InjectedFileViewProvider viewProvider,
@NotNull PsiFile psiFile,
@NotNull SmartPsiElementPointer<PsiLanguageInjectionHost> pointer) {
FileDocumentManagerImpl.registerDocument(documentWindow, viewProvider.getVirtualFile());
viewProvider.forceCachedPsi(psiFile);
@@ -309,7 +308,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
keepTreeFromChameleoningBack(psiFile);
viewProvider.setShreds(place);
return viewProvider.setShreds(place, psiFile.getProject());
}
@@ -505,4 +504,22 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
}
return tokens;
}
// for CachedValue
@Override
public long getModificationCount() {
List<PsiLanguageInjectionHost.Shred> shredList = shreds;
if (shredList != null) {
for (PsiLanguageInjectionHost.Shred shred : shredList) {
if (!shred.isValid()) return -1;
}
}
DocumentEx hostDocument = myHostDocument;
return hostDocument == null ? -1 : hostDocument.getModificationStamp();
}
@Override
public String toString() {
return result.toString();
}
}
@@ -834,11 +834,13 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
final SortedMap<Integer, List<GutterIconRenderer>> result = new TreeMap<Integer, List<GutterIconRenderer>>();
configureByFilesInner(filePath);
for (HighlightInfo info : doHighlighting()) {
List<HighlightInfo> infos = doHighlighting();
for (HighlightInfo info : infos) {
addGutterIconRenderer(info.getGutterIconRenderer(), info.startOffset, result);
}
for (final RangeHighlighter highlighter : DocumentMarkupModel.forDocument(myEditor.getDocument(), project, true).getAllHighlighters()) {
RangeHighlighter[] highlighters = DocumentMarkupModel.forDocument(myEditor.getDocument(), project, true).getAllHighlighters();
for (final RangeHighlighter highlighter : highlighters) {
if (!highlighter.isValid()) continue;
addGutterIconRenderer(highlighter.getGutterIconRenderer(), highlighter.getStartOffset(), result);
}
@@ -1368,13 +1370,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
final Project project = getProject();
PsiDocumentManager.getInstance(project).commitAllDocuments();
return
ApplicationManager.getApplication().runReadAction(new Computable<List<HighlightInfo>>() {
@Override
public List<HighlightInfo> compute() {
return instantiateAndRun(getFile(), getEditor(), ArrayUtil.EMPTY_INT_ARRAY, myAllowDirt);
}
});
return instantiateAndRun(getFile(), getEditor(), ArrayUtil.EMPTY_INT_ARRAY, myAllowDirt);
}
@NotNull