@NotNull private static PsiExpression getTopLevel(Project project, @NotNull PsiExpression expression) { int i = 0; while (expression.getParent() instanceof PsiExpression) { i++; final PsiExpression parent = (PsiExpression)expression.getParent(); if (parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() == expression) break; expression = parent; if (expression instanceof PsiAssignmentExpression) break; if (i > 10 && expression instanceof PsiBinaryExpression) { ParameterizedCachedValue<PsiExpression, Pair<Project, PsiExpression>> value = expression.getUserData(TOP_LEVEL_EXPRESSION); if (value != null && value.hasUpToDateValue()) { return getToplevelExpression(project, expression); // optimization: use caching for big hierarchies } } } return expression; }
@Override public boolean hasFacets(@NotNull FacetTypeId<?> typeId) { ParameterizedCachedValue<Boolean, FacetTypeId<?>> value = myCachedHasFacets.get(typeId); if (value == null) { value = CachedValuesManager.getManager(myProject).createParameterizedCachedValue(myCachedValueProvider, false); myCachedHasFacets.put(typeId, value); } return value.getValue(typeId); }
@Nullable static Runnable updateFoldRegions(@Nonnull final Editor editor, @Nonnull PsiFile file, final boolean applyDefaultState, final boolean quick) { ApplicationManager.getApplication().assertReadAccessAllowed(); final Project project = file.getProject(); final Document document = editor.getDocument(); LOG.assertTrue(!PsiDocumentManager.getInstance(project).isUncommited(document)); String currentFileExtension = null; final VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile != null) { currentFileExtension = virtualFile.getExtension(); } ParameterizedCachedValue<Runnable, Boolean> value = editor.getUserData(CODE_FOLDING_KEY); if (value != null) { // There was a problem that old fold regions have been cached on file extension change (e.g. *.java -> *.groovy). // We want to drop them in such circumstances. final String oldExtension = editor.getUserData(CODE_FOLDING_FILE_EXTENSION_KEY); if (oldExtension == null ? currentFileExtension != null : !oldExtension.equals(currentFileExtension)) { value = null; editor.putUserData(CODE_FOLDING_KEY, null); } } editor.putUserData(CODE_FOLDING_FILE_EXTENSION_KEY, currentFileExtension); if (value != null && value.hasUpToDateValue() && !applyDefaultState) return value.getValue(null); // param shouldn't matter, as the value is up-to-date if (quick) return getUpdateResult(file, document, true, project, editor, applyDefaultState).getValue(); return CachedValuesManager.getManager(project).getParameterizedCachedValue( editor, CODE_FOLDING_KEY, param -> { Document document1 = editor.getDocument(); PsiFile file1 = PsiDocumentManager.getInstance(project).getPsiFile(document1); return getUpdateResult(file1, document1, false, project, editor, param); }, false, applyDefaultState); }
@Override protected ParameterizedCachedValue<List<JSClass>, Object> compute(final JSClassBase jsClassBase, final Object p) { return CachedValuesManager.getManager(jsClassBase.getProject()).createParameterizedCachedValue(new ParameterizedCachedValueProvider<List<JSClass>, Object>() { @Override public CachedValueProvider.Result<List<JSClass>> compute(Object list) { return new CachedValueProvider.Result<List<JSClass>>(doCompute(list), PsiModificationTracker.MODIFICATION_COUNT); } }, false); }
@NotNull private static ParameterizedCachedValue<Map<GlobalSearchScope, MembersMap>, PsiClass> getValues(@NotNull PsiClass aClass) { ParameterizedCachedValue<Map<GlobalSearchScope, MembersMap>, PsiClass> value = aClass.getUserData(MAP_IN_CLASS_KEY); if(value == null) { value = CachedValuesManager.getManager(aClass.getProject()).createParameterizedCachedValue(ByNameCachedValueProvider.INSTANCE, false); //Do not cache for nonphysical elements if(aClass.isPhysical()) { value = ((UserDataHolderEx) aClass).putUserDataIfAbsent(MAP_IN_CLASS_KEY, value); } } return value; }
@Override protected ParameterizedCachedValue<Map<Pair<QName,Integer>,Function>,XmlFile> compute(XmlFile file, Void p) { return CachedValuesManager.getManager(file.getProject()).createParameterizedCachedValue(MyFunctionProvider.INSTANCE, false); }
private static <D extends PsiElement, T, P> T getCachedValue(D context, P p, Key<ParameterizedCachedValue<T, P>> key, ParameterizedCachedValueProvider<T, P> provider) { final CachedValuesManager mgr = CachedValuesManager.getManager(context.getProject()); return mgr.getParameterizedCachedValue(context, key, provider, false, p); }
@Override protected ParameterizedCachedValue<Set<String>, JSElement> compute(JSElement jsElement, Object p) { return CachedValuesManager.getManager(jsElement.getProject()).createParameterizedCachedValue(new ParameterizedCachedValueProvider<Set<String>, JSElement>() { @Override public CachedValueProvider.Result<Set<String>> compute(JSElement context) { class MyProcessor extends ResolveProcessor implements Processor<PsiNamedElement> { Set<String> openedNses; public MyProcessor() { super(null); putUserData(ResolveProcessor.LOOKING_FOR_USE_NAMESPACES, true); } @Override public boolean process(PsiNamedElement psiNamedElement) { if(psiNamedElement instanceof JSElement) { processDeclarationsInScope((JSElement) psiNamedElement, this, ResolveState.initial(), psiNamedElement, psiNamedElement); } else { // TODO: XmlFile ? } return true; } @Override public boolean execute(PsiElement element, ResolveState state) { if(!(element instanceof JSUseNamespaceDirective)) { return true; } if(openedNses == null) { openedNses = new THashSet<String>(); } openedNses.add(((JSUseNamespaceDirective) element).getNamespaceToBeUsed()); return true; } } MyProcessor processor = new MyProcessor(); walkOverStructure(context, processor); return new CachedValueProvider.Result<Set<String>>(processor.openedNses, PsiModificationTracker.EVER_CHANGED); } }, false); }
private static Map<String, PsiMember[]> getMap(@NotNull PsiClass aClass, @NotNull MemberType type) { ParameterizedCachedValue<Map<GlobalSearchScope, MembersMap>, PsiClass> value = getValues(aClass); return value.getValue(aClass).get(aClass.getResolveScope()).get(type); }
@Override public void injectLanguages(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) { if(myManager.myConcatenationInjectors.isEmpty()) { return; } final PsiFile containingFile = ((InjectionRegistrarImpl) registrar).getHostPsiFile(); Project project = containingFile.getProject(); long modificationCount = PsiManager.getInstance(project).getModificationTracker().getModificationCount(); Pair<PsiElement, PsiElement[]> pair = computeAnchorAndOperands(context); PsiElement anchor = pair.first; PsiElement[] operands = pair.second; Integer noInjectionTimestamp = anchor.getUserData(NO_CONCAT_INJECTION_TIMESTAMP); InjectionResult result; ParameterizedCachedValue<InjectionResult, PsiElement> data = null; if(operands.length == 0 || noInjectionTimestamp != null && noInjectionTimestamp == modificationCount) { result = null; } else { data = anchor.getUserData(INJECTED_PSI_IN_CONCATENATION); result = data == null ? null : data.getValue(context); if(result == null || !result.isValid()) { result = doCompute(containingFile, project, anchor, operands); } } if(result != null) { ((InjectionRegistrarImpl) registrar).addToResults(result); if(data == null) { CachedValueProvider.Result<InjectionResult> cachedResult = CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT, myManager); data = CachedValuesManager.getManager(project).createParameterizedCachedValue(context1 -> { PsiFile containingFile1 = context1.getContainingFile(); Project project1 = containingFile1.getProject(); Pair<PsiElement, PsiElement[]> pair1 = computeAnchorAndOperands(context1); InjectionResult result1 = pair1.second.length == 0 ? null : doCompute(containingFile1, project1, pair1.first, pair1.second); return result1 == null ? null : CachedValueProvider.Result.create(result1, PsiModificationTracker.MODIFICATION_COUNT, myManager); }, false); ((PsiParameterizedCachedValue<InjectionResult, PsiElement>) data).setValue(cachedResult); anchor.putUserData(INJECTED_PSI_IN_CONCATENATION, data); if(anchor.getUserData(NO_CONCAT_INJECTION_TIMESTAMP) != null) { anchor.putUserData(NO_CONCAT_INJECTION_TIMESTAMP, null); } } } else { // cache no-injection flag if(anchor.getUserData(INJECTED_PSI_IN_CONCATENATION) != null) { anchor.putUserData(INJECTED_PSI_IN_CONCATENATION, null); } anchor.putUserData(NO_CONCAT_INJECTION_TIMESTAMP, (int) modificationCount); } }
<T,P> ParameterizedCachedValue<T,P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T,P> provider, boolean trackValue);
<T,P> ParameterizedCachedValue<T,P> createParameterizedCachedValue(@Nonnull ParameterizedCachedValueProvider<T,P> provider, boolean trackValue);