Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
Dmitry Trofimov
2010-07-29 17:23:14 +04:00
83 changed files with 1988 additions and 1034 deletions
@@ -973,7 +973,7 @@ public class CompileDriver {
if (context.getProgressIndicator().isCanceled()) {
throw new ExitException(ExitStatus.CANCELLED);
}
context.getProgressIndicator().setText("Preparing sources for " + compiler.getDescription());
DumbService.getInstance(myProject).waitForSmartMode();
if (round == 0) {
@@ -76,6 +76,10 @@ public class AnnotationProcessingCompiler implements TranslatingCompiler{
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
return path != null? lfs.findFileByPath(path) : null;
}
public VirtualFile getModuleOutputDirectoryForTests(Module module) {
return getModuleOutputDirectory(module);
}
};
final JavacCompiler javacCompiler = getBackEndCompiler();
final boolean processorMode = javacCompiler.setAnnotationProcessorMode(true);
@@ -21,7 +21,6 @@
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.EditorBundle;
import com.intellij.openapi.editor.HectorComponentPanel;
import com.intellij.openapi.editor.HectorComponentPanelsProvider;
@@ -30,13 +29,11 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiFile;
import com.intellij.util.ui.DialogUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.Set;
public class ImportPopupHectorComponentProvider implements HectorComponentPanelsProvider {
@@ -48,8 +45,6 @@ public class ImportPopupHectorComponentProvider implements HectorComponentPanels
assert virtualFile != null;
final boolean notInLibrary =
!fileIndex.isInLibrarySource(virtualFile) && !fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInContent(virtualFile);
final FileViewProvider viewProvider = file.getViewProvider();
final Set<Language> languages = viewProvider.getLanguages();
return new HectorComponentPanel() {
private JCheckBox myImportPopupCheckBox = new JCheckBox(EditorBundle.message("hector.import.popup.checkbox"));
@@ -3,17 +3,15 @@
*/
package com.intellij.psi.impl.search;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadActionProcessor;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightMemberReference;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.psi.search.SearchRequestCollector;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.PairProcessor;
import com.intellij.util.Processor;
/**
@@ -30,38 +28,29 @@ public class ConstructorReferencesSearchHelper {
final PsiMethod constructor,
final SearchScope searchScope,
boolean ignoreAccessScope,
final boolean isStrictSignatureSearch) {
final Ref<Boolean> result = new Ref<Boolean>();
PsiClass aClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
public PsiClass compute() {
PsiClass aClass = constructor.getContainingClass();
if (aClass == null) {
result.set(true);
return null;
}
final boolean isStrictSignatureSearch, SearchRequestCollector collector) {
PsiClass aClass = constructor.getContainingClass();
if (aClass == null) {
return true;
}
if (aClass.isEnum()) {
PsiField[] fields = aClass.getFields();
for (PsiField field : fields) {
if (field instanceof PsiEnumConstant) {
PsiReference reference = field.getReference();
if (reference != null && reference.isReferenceTo(constructor)) {
if (!processor.process(reference)) {
result.set(false);
return null;
}
}
if (aClass.isEnum()) {
for (PsiField field : aClass.getFields()) {
if (field instanceof PsiEnumConstant) {
PsiReference reference = field.getReference();
if (reference != null && reference.isReferenceTo(constructor)) {
if (!processor.process(reference)) {
return false;
}
}
}
return aClass;
}
});
if (!result.isNull()) return result.get();
}
// search usages like "new XXX(..)"
Processor<PsiReference> processor1 = new ReadActionProcessor<PsiReference>() {
public boolean processInReadAction(final PsiReference reference) {
PairProcessor<PsiReference, SearchRequestCollector> processor1 = new PairProcessor<PsiReference, SearchRequestCollector>() {
@Override
public boolean process(PsiReference reference, SearchRequestCollector collector) {
PsiElement parent = reference.getElement().getParent();
if (parent instanceof PsiAnonymousClass) {
parent = parent.getParent();
@@ -85,12 +74,12 @@ public class ConstructorReferencesSearchHelper {
}
};
if (!ReferencesSearch.search(aClass, searchScope, ignoreAccessScope).forEach(processor1)) return false;
ReferencesSearch.searchOptimized(aClass, searchScope, ignoreAccessScope, collector, true, processor1);
final boolean constructorCanBeCalledImplicitly = constructor.getParameterList().getParametersCount() == 0;
// search usages like "this(..)"
if (!processSuperOrThis(processor, aClass, constructor, constructorCanBeCalledImplicitly, searchScope, isStrictSignatureSearch,
PsiKeyword.THIS)) {
PsiKeyword.THIS)) {
return false;
}
@@ -98,7 +87,7 @@ public class ConstructorReferencesSearchHelper {
Processor<PsiClass> processor2 = new Processor<PsiClass>() {
public boolean process(PsiClass inheritor) {
return processSuperOrThis(processor, (PsiClass)inheritor.getNavigationElement(), constructor, constructorCanBeCalledImplicitly, searchScope, isStrictSignatureSearch,
PsiKeyword.SUPER);
PsiKeyword.SUPER);
}
};
@@ -110,21 +99,6 @@ public class ConstructorReferencesSearchHelper {
final PsiMethod constructor, final boolean constructorCanBeCalledImplicitly, final SearchScope searchScope,
final boolean isStrictSignatureSearch,
final String superOrThisKeyword) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
return processSuperOrThisInReadAction(inheritor, searchScope, superOrThisKeyword, isStrictSignatureSearch, constructor,
constructorCanBeCalledImplicitly, processor);
}
});
}
private boolean processSuperOrThisInReadAction(final PsiClass inheritor,
final SearchScope searchScope,
final String superOrThisKeyword,
final boolean isStrictSignatureSearch,
final PsiMethod constructor,
final boolean constructorCanBeCalledImplicitly,
final Processor<PsiReference> processor) {
PsiMethod[] constructors = inheritor.getConstructors();
if (constructors.length == 0 && constructorCanBeCalledImplicitly) {
processImplicitConstructorCall(inheritor, processor, constructor, inheritor);
@@ -3,24 +3,28 @@
*/
package com.intellij.psi.impl.search;
import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
/**
* @author max
*/
public class ConstructorReferencesSearcher implements QueryExecutor<PsiReference, ReferencesSearch.SearchParameters> {
public boolean execute(final ReferencesSearch.SearchParameters p, final Processor<PsiReference> consumer) {
public class ConstructorReferencesSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {
protected ConstructorReferencesSearcher() {
super(true);
}
@Override
public void processQuery(ReferencesSearch.SearchParameters p, Processor<PsiReference> consumer) {
final PsiElement element = p.getElementToSearch();
if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) {
return new ConstructorReferencesSearchHelper(PsiManager.getInstance(element.getProject()))
.processConstructorReferences(consumer, (PsiMethod)p.getElementToSearch(), p.getScope(), p.isIgnoreAccessScope(), true);
new ConstructorReferencesSearchHelper(PsiManager.getInstance(element.getProject()))
.processConstructorReferences(consumer, (PsiMethod)p.getElementToSearch(), p.getScope(), p.isIgnoreAccessScope(), true, p.getOptimizer());
}
return true;
}
}
@@ -3,9 +3,7 @@
*/
package com.intellij.psi.impl.search;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.SearchRequestCollector;
import com.intellij.psi.search.SearchScope;
@@ -18,6 +16,9 @@ import com.intellij.util.Processor;
* @author max
*/
public class MethodUsagesSearcher extends QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters> {
protected MethodUsagesSearcher() {
super(true);
}
@Override
public void processQuery(MethodReferencesSearch.SearchParameters p, Processor<PsiReference> consumer) {
@@ -28,60 +29,42 @@ public class MethodUsagesSearcher extends QueryExecutorBase<PsiReference, Method
final PsiManager psiManager = PsiManager.getInstance(method.getProject());
final PsiClass aClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
public PsiClass compute() {
return method.isValid() ? method.getContainingClass() : null;
}
});
final PsiClass aClass = method.getContainingClass();
if (aClass == null) return;
final boolean strictSignatureSearch = p.isStrictSignatureSearch();
if (method.isConstructor()) {
collector.searchCustom(new Processor<Processor<PsiReference>>() {
public boolean process(Processor<PsiReference> consumer) {
return new ConstructorReferencesSearchHelper(psiManager).
processConstructorReferences(consumer, method, searchScope, !strictSignatureSearch, strictSignatureSearch);
}
});
new ConstructorReferencesSearchHelper(psiManager).
processConstructorReferences(consumer, method, searchScope, !strictSignatureSearch, strictSignatureSearch, collector);
}
boolean needStrictSignatureSearch = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
return method.isValid() && strictSignatureSearch && (aClass instanceof PsiAnonymousClass
boolean needStrictSignatureSearch = strictSignatureSearch && (aClass instanceof PsiAnonymousClass
|| aClass.hasModifierProperty(PsiModifier.FINAL)
|| method.hasModifierProperty(PsiModifier.STATIC)
|| method.hasModifierProperty(PsiModifier.FINAL)
|| method.hasModifierProperty(PsiModifier.PRIVATE));
}
});
if (needStrictSignatureSearch) {
ReferencesSearch.search(new ReferencesSearch.SearchParameters(method, searchScope, false, collector)).forEach(consumer);
ReferencesSearch.searchOptimized(method, searchScope, false, collector, consumer);
return;
}
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (!method.isValid()) return;
final String textToSearch = method.getName();
final PsiMethod[] methods = strictSignatureSearch ? new PsiMethod[]{method} : aClass.findMethodsByName(textToSearch, false);
final String textToSearch = method.getName();
final PsiMethod[] methods = strictSignatureSearch ? new PsiMethod[]{method} : aClass.findMethodsByName(textToSearch, false);
SearchScope accessScope = methods[0].getUseScope();
for (int i = 1; i < methods.length; i++) {
PsiMethod method1 = methods[i];
accessScope = accessScope.union(method1.getUseScope());
}
SearchScope accessScope = methods[0].getUseScope();
for (int i = 1; i < methods.length; i++) {
PsiMethod method1 = methods[i];
accessScope = accessScope.union(method1.getUseScope());
}
final SearchScope restrictedByAccess = searchScope.intersectWith(accessScope);
final SearchScope restrictedByAccess = searchScope.intersectWith(accessScope);
short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_COMMENTS | UsageSearchContext.IN_FOREIGN_LANGUAGES;
collector.searchWord(textToSearch, restrictedByAccess, searchContext, true,
new MethodTextOccurrenceProcessor(aClass, strictSignatureSearch, methods));
short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_COMMENTS | UsageSearchContext.IN_FOREIGN_LANGUAGES;
collector.searchWord(textToSearch, restrictedByAccess, searchContext, true,
new MethodTextOccurrenceProcessor(aClass, strictSignatureSearch, methods));
SimpleAccessorReferenceSearcher.addPropertyAccessUsages(method, restrictedByAccess, collector);
}
});
SimpleAccessorReferenceSearcher.addPropertyAccessUsages(method, restrictedByAccess, collector);
}
@@ -17,14 +17,10 @@ package com.intellij.psi.search.searches;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.SearchRequestCollector;
import com.intellij.psi.search.SearchRequestQuery;
import com.intellij.psi.search.SearchScope;
import com.intellij.util.MergeQuery;
import com.intellij.util.Query;
import com.intellij.util.UniqueResultsQuery;
import com.intellij.psi.search.*;
import com.intellij.util.*;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
@@ -75,6 +71,21 @@ public class MethodReferencesSearch extends ExtensibleQueryFactory<PsiReference,
return search(new SearchParameters(method, scope, strictSignatureSearch));
}
public static void searchOptimized(final PsiMethod method, SearchScope scope, final boolean strictSignatureSearch,
@NotNull SearchRequestCollector collector, final Processor<PsiReference> processor) {
searchOptimized(method, scope, strictSignatureSearch, collector, false, new PairProcessor<PsiReference, SearchRequestCollector>() {
@Override
public boolean process(PsiReference psiReference, SearchRequestCollector collector) {
return processor.process(psiReference);
}
});
}
public static void searchOptimized(final PsiMethod method, SearchScope scope, final boolean strictSignatureSearch, SearchRequestCollector collector, final boolean inReadAction, PairProcessor<PsiReference, SearchRequestCollector> processor) {
final SearchRequestCollector nested = new SearchRequestCollector();
collector.searchQuery(new QuerySearchRequest(search(new SearchParameters(method, scope, strictSignatureSearch, nested)), nested,
inReadAction, processor));
}
public static Query<PsiReference> search(final SearchParameters parameters) {
final Query<PsiReference> result = INSTANCE.createQuery(parameters);
if (parameters.isSharedOptimizer) {
@@ -16,13 +16,12 @@
package com.intellij.execution.ui;
import com.intellij.openapi.ui.ComponentContainer;
import javax.swing.*;
import org.jetbrains.annotations.NonNls;
/**
* @author Eugene Zhuravlev
* Date: Apr 20, 2004
*/
public interface ExecutionConsole extends ComponentContainer {
@NonNls String CONSOLE_CONTENT_ID = "ConsoleContent";
}
@@ -0,0 +1,27 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.documentation;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
/**
* User: spLeaner
*/
public interface ExternalDocumentationHandler {
boolean handleExternal(PsiElement element, PsiElement originalElement);
boolean handleExternalLink(PsiManager psiManager, String link, PsiElement context);
}
@@ -45,6 +45,7 @@ public interface CustomHighlighterTokenType {
IElementType MULTI_LINE_COMMENT = new CustomElementType("MULTI_LINE_COMMENT");
IElementType WHITESPACE = new CustomElementType("WHITESPACE");
IElementType CHARACTER = new CustomElementType("CHARACTER");
IElementType PUNCTUATION = new CustomElementType("PUNCTUATION");
IElementType L_BRACE = new CustomElementType("L_BRACE");
IElementType R_BRACE = new CustomElementType("R_BRACE");
@@ -107,23 +107,11 @@ public abstract class PsiReferenceBase<T extends PsiElement> implements PsiRefer
}
public static <T extends PsiElement> PsiReferenceBase<T> createSelfReference(T element, final PsiElement resolveTo) {
return new Immediate<T>(element, true, resolveTo);
}
return new PsiReferenceBase<T>(element,true) {
//do nothing. the element will be renamed via PsiMetaData (com.intellij.refactoring.rename.RenameUtil.doRenameGenericNamedElement())
public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException {
return getElement();
}
@Nullable
public PsiElement resolve() {
return resolveTo;
}
@NotNull
public Object[] getVariants() {
return EMPTY_ARRAY;
}
};
public static <T extends PsiElement> PsiReferenceBase<T> createSelfReference(T element, TextRange range, final PsiElement resolveTo) {
return new Immediate<T>(element, range, resolveTo);
}
@Nullable
@@ -165,4 +153,43 @@ public abstract class PsiReferenceBase<T extends PsiElement> implements PsiRefer
return resolveResults.length == 1 ? resolveResults[0].getElement() : null;
}
}
public static class Immediate<T extends PsiElement> extends PsiReferenceBase<T> {
private final PsiElement myResolveTo;
public Immediate(T element, TextRange range, boolean soft, PsiElement resolveTo) {
super(element, range, soft);
myResolveTo = resolveTo;
}
public Immediate(T element, TextRange range, PsiElement resolveTo) {
super(element, range);
myResolveTo = resolveTo;
}
public Immediate(T element, boolean soft, PsiElement resolveTo) {
super(element, soft);
myResolveTo = resolveTo;
}
public Immediate(@NotNull T element, PsiElement resolveTo) {
super(element);
myResolveTo = resolveTo;
}
//do nothing. the element will be renamed via PsiMetaData (com.intellij.refactoring.rename.RenameUtil.doRenameGenericNamedElement())
public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException {
return getElement();
}
@Nullable
public PsiElement resolve() {
return myResolveTo;
}
@NotNull
public Object[] getVariants() {
return EMPTY_ARRAY;
}
}
}
@@ -25,4 +25,8 @@ public class PsiSearchRequest {
this.processor = processor;
}
@Override
public String toString() {
return "PsiSearchRequest: " + word + "; " + processor;
}
}
@@ -0,0 +1,43 @@
package com.intellij.psi.search;
import com.intellij.openapi.application.ReadActionProcessor;
import com.intellij.psi.PsiReference;
import com.intellij.util.PairProcessor;
import com.intellij.util.Processor;
import com.intellij.util.Query;
/**
* @author peter
*/
public class QuerySearchRequest {
public final Query<PsiReference> query;
public final SearchRequestCollector collector;
public final Processor<PsiReference> processor;
public QuerySearchRequest(Query<PsiReference> query,
final SearchRequestCollector collector,
boolean inReadAction, final PairProcessor<PsiReference, SearchRequestCollector> processor) {
this.query = query;
this.collector = collector;
if (inReadAction) {
this.processor = new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(PsiReference psiReference) {
return processor.process(psiReference, collector);
}
};
} else {
this.processor = new Processor<PsiReference>() {
@Override
public boolean process(PsiReference psiReference) {
return processor.process(psiReference, collector);
}
};
}
}
public void runQuery() {
query.forEach(processor);
}
}
@@ -3,6 +3,7 @@ package com.intellij.psi.search;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.util.Processor;
import com.intellij.util.containers.CollectionFactory;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -12,8 +13,10 @@ import java.util.List;
* @author peter
*/
public class SearchRequestCollector {
private final List<PsiSearchRequest> myRequests = new ArrayList<PsiSearchRequest>();
private final List<Processor<Processor<PsiReference>>> myCustomSearchActions = new ArrayList<Processor<Processor<PsiReference>>>();
private final Object lock = new Object();
private final List<PsiSearchRequest> myWordRequests = CollectionFactory.arrayList();
private final List<QuerySearchRequest> myQueryRequests = CollectionFactory.arrayList();
private final List<Processor<Processor<PsiReference>>> myCustomSearchActions = CollectionFactory.arrayList();
public void searchWord(@NotNull String word, @NotNull SearchScope searchScope, boolean caseSensitive, @NotNull PsiElement searchTarget) {
final short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_FOREIGN_LANGUAGES | UsageSearchContext.IN_COMMENTS;
@@ -29,18 +32,48 @@ public class SearchRequestCollector {
return;
}
myRequests.add(new PsiSearchRequest(searchScope, word, searchContext, caseSensitive, processor));
synchronized (lock) {
myWordRequests.add(new PsiSearchRequest(searchScope, word, searchContext, caseSensitive, processor));
}
}
public void searchQuery(QuerySearchRequest request) {
assert request.collector != this;
synchronized (lock) {
myQueryRequests.add(request);
}
}
public void searchCustom(Processor<Processor<PsiReference>> searchAction) {
myCustomSearchActions.add(searchAction);
synchronized (lock) {
myCustomSearchActions.add(searchAction);
}
}
public List<PsiSearchRequest> getSearchRequests() {
return myRequests;
public boolean hasRequests() {
synchronized (lock) {
return !myWordRequests.isEmpty() || !myCustomSearchActions.isEmpty() || !myQueryRequests.isEmpty();
}
}
public List<Processor<Processor<PsiReference>>> getCustomSearchActions() {
return myCustomSearchActions;
public List<QuerySearchRequest> takeQueryRequests() {
return takeRequests(myQueryRequests);
}
private <T> List<T> takeRequests(List<T> list) {
synchronized (lock) {
final List<T> requests = new ArrayList<T>(list);
requests.addAll(list);
list.clear();
return requests;
}
}
public List<PsiSearchRequest> takeSearchRequests() {
return takeRequests(myWordRequests);
}
public List<Processor<Processor<PsiReference>>> takeCustomSearchActions() {
return takeRequests(myCustomSearchActions);
}
}
@@ -17,10 +17,7 @@ package com.intellij.psi.search.searches;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.SearchRequestCollector;
import com.intellij.psi.search.SearchRequestQuery;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.*;
import com.intellij.util.*;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
@@ -111,4 +108,21 @@ public class ReferencesSearch extends ExtensibleQueryFactory<PsiReference, Refer
return new UniqueResultsQuery(composite, TObjectHashingStrategy.CANONICAL, ReferenceDescriptor.MAPPER);
}
public static void searchOptimized(@NotNull PsiElement element, @NotNull SearchScope searchScope, boolean ignoreAccessScope,
@NotNull SearchRequestCollector collector, final Processor<PsiReference> processor) {
searchOptimized(element, searchScope, ignoreAccessScope, collector, false, new PairProcessor<PsiReference, SearchRequestCollector>() {
@Override
public boolean process(PsiReference psiReference, SearchRequestCollector collector) {
return processor.process(psiReference);
}
});
}
public static void searchOptimized(@NotNull PsiElement element, @NotNull SearchScope searchScope, boolean ignoreAccessScope,
@NotNull SearchRequestCollector collector, final boolean inReadAction, PairProcessor<PsiReference, SearchRequestCollector> processor) {
final SearchRequestCollector nested = new SearchRequestCollector();
collector.searchQuery(new QuerySearchRequest(search(new SearchParameters(element, searchScope, ignoreAccessScope, nested)), nested,
inReadAction, processor));
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.daemon;
import com.intellij.ide.PowerSaveMode;
import com.intellij.openapi.editor.HectorComponentPanel;
import com.intellij.openapi.editor.HectorComponentPanelsProvider;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* @author yole
*/
public class PowerSaveHectorProvider implements HectorComponentPanelsProvider {
@Override
public HectorComponentPanel createConfigurable(@NotNull PsiFile file) {
return new HectorComponentPanel() {
private JCheckBox myCheckBox = new JCheckBox("Power Save Mode");
@Override
public JComponent createComponent() {
return myCheckBox;
}
@Override
public boolean isModified() {
return myCheckBox.isSelected() != PowerSaveMode.isEnabled();
}
@Override
public void apply() throws ConfigurationException {
PowerSaveMode.setEnabled(myCheckBox.isSelected());
}
@Override
public void reset() {
myCheckBox.setSelected(PowerSaveMode.isEnabled());
}
@Override
public void disposeUIResources() {
}
};
}
}
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.daemon.ReferenceImporter;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
import com.intellij.concurrency.Job;
import com.intellij.ide.PowerSaveMode;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -586,6 +587,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx
return new Runnable() {
public void run() {
if (!myUpdateByTimerEnabled) return;
if (PowerSaveMode.isEnabled()) return;
if (myDisposed || myProject.isDisposed()) return;
final Collection<FileEditor> activeEditors = myDaemonListeners.getSelectedEditors();
if (activeEditors.isEmpty()) return;
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.daemon.impl;
import com.intellij.ProjectTopics;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.hint.TooltipController;
import com.intellij.ide.PowerSaveMode;
import com.intellij.ide.todo.TodoConfiguration;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
@@ -195,6 +196,13 @@ public class DaemonListeners implements Disposable {
}
});
connection.subscribe(PowerSaveMode.TOPIC, new PowerSaveMode.Listener() {
@Override
public void powerSaveStateChanged() {
stopDaemon(true);
}
});
CommandProcessor.getInstance().addCommandListener(new MyCommandListener(), this);
ApplicationManager.getApplication().addApplicationListener(myApplicationListener);
EditorColorsManager.getInstance().addEditorColorsListener(myEditorColorsListener);
@@ -20,6 +20,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeInsight.daemon.DaemonBundle;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil;
import com.intellij.ide.PowerSaveMode;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.markup.ErrorStripeRenderer;
@@ -109,7 +110,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer {
final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(myProject);
status.errorCount = new int[severityRegistrar.getSeveritiesCount()];
status.rootsNumber = roots.length;
fillDaemonCodeAnalyzerErrorsSatus(status, fillErrorsCount);
fillDaemonCodeAnalyzerErrorsStatus(status, fillErrorsCount);
List<TextEditorHighlightingPass> passes = myDaemonCodeAnalyzer.getPassesToShowProgressFor(myFile);
ArrayList<DaemonCodeAnalyzerStatus.PassStatus> passStati = new ArrayList<DaemonCodeAnalyzerStatus.PassStatus>();
for (TextEditorHighlightingPass tepass : passes) {
@@ -127,7 +128,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer {
return status;
}
protected void fillDaemonCodeAnalyzerErrorsSatus(DaemonCodeAnalyzerStatus status, boolean fillErrorsCount) {
protected void fillDaemonCodeAnalyzerErrorsStatus(DaemonCodeAnalyzerStatus status, boolean fillErrorsCount) {
final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(myProject);
List<HighlightInfo> highlights = DaemonCodeAnalyzerImpl.getHighlights(myDocument, myProject);
if (highlights == null) highlights = Arrays.asList(HighlightInfo.EMPTY_ARRAY);
@@ -185,6 +186,11 @@ public class TrafficLightRenderer implements ErrorStripeRenderer {
if (status == null) return null;
@NonNls String text = HTML_HEADER;
if (PowerSaveMode.isEnabled()) {
text += "Code analysis is disabled in power save mode.";
text += HTML_FOOTER;
return text;
}
if (status.noHighlightingRoots != null && status.noHighlightingRoots.length == status.rootsNumber) {
text += DaemonBundle.message("analysis.hasnot.been.run");
text += HTML_FOOTER;
@@ -22,6 +22,7 @@ import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.ide.actions.ExternalJavaDocAction;
import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.lang.documentation.ExternalDocumentationHandler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.ui.popup.JBPopup;
@@ -405,10 +406,13 @@ public class DocumentationComponent extends JPanel implements Disposable {
if (myElement != null) {
final PsiElement element = myElement.getElement();
final DocumentationProvider provider = DocumentationManager.getProviderFromElement(element);
final List<String> urls = provider.getUrlFor(element, DocumentationManager.getOriginalElement(element));
assert urls != null;
assert !urls.isEmpty();
ExternalJavaDocAction.showExternalJavadoc(urls);
final PsiElement originalElement = DocumentationManager.getOriginalElement(element);
if (!(provider instanceof ExternalDocumentationHandler) || !((ExternalDocumentationHandler)provider).handleExternal(element, originalElement)) {
final List<String> urls = provider.getUrlFor(element, originalElement);
assert urls != null;
assert !urls.isEmpty();
ExternalJavaDocAction.showExternalJavadoc(urls);
}
}
}
@@ -33,6 +33,7 @@ import com.intellij.lang.Language;
import com.intellij.lang.LanguageDocumentation;
import com.intellij.lang.documentation.CompositeDocumentationProvider;
import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.lang.documentation.ExternalDocumentationHandler;
import com.intellij.lang.documentation.ExternalDocumentationProvider;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
@@ -816,38 +817,43 @@ public class DocumentationManager {
}
}
else {
final DocumentationProvider provider = getProviderFromElement(psiElement);
if (!(provider instanceof ExternalDocumentationHandler) ||
!((ExternalDocumentationHandler)provider).handleExternalLink(manager, url, psiElement)) {
final String docUrl = url;
fetchDocInfo
(new DocumentationCollector() {
public String getDocumentation() throws Exception {
if (docUrl.startsWith(DOC_ELEMENT_PROTOCOL)) {
final List<String> urls = ApplicationManager.getApplication().runReadAction(
fetchDocInfo
(new DocumentationCollector() {
public String getDocumentation() throws Exception {
if (docUrl.startsWith(DOC_ELEMENT_PROTOCOL)) {
final List<String> urls = ApplicationManager.getApplication().runReadAction(
new Computable<List<String>>() {
public List<String> compute() {
final DocumentationProvider provider = getProviderFromElement(psiElement);
return provider.getUrlFor(psiElement, getOriginalElement(psiElement));
}
}
);
BrowserUtil.launchBrowser(urls != null && !urls.isEmpty() ? urls.get(0) : docUrl);
} else {
BrowserUtil.launchBrowser(docUrl);
);
BrowserUtil.launchBrowser(urls != null && !urls.isEmpty() ? urls.get(0) : docUrl);
}
else {
BrowserUtil.launchBrowser(docUrl);
}
return "";
}
return "";
}
public PsiElement getElement() {
//String loc = getElementLocator(docUrl);
//
//if (loc != null) {
// PsiElement context = component.getElement();
// return JavaDocUtil.findReferenceTarget(context.getManager(), loc, context);
//}
public PsiElement getElement() {
//String loc = getElementLocator(docUrl);
//
//if (loc != null) {
// PsiElement context = component.getElement();
// return JavaDocUtil.findReferenceTarget(context.getManager(), loc, context);
//}
return psiElement;
}
}, component);
return psiElement;
}
}, component);
}
}
component.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
@@ -157,7 +157,7 @@ public class RunContentBuilder implements LogConsoleManager, Disposable {
}
}
final Content consoleContent = ui.createContent("Console", console.getComponent(), "Console",
final Content consoleContent = ui.createContent(ExecutionConsole.CONSOLE_CONTENT_ID, console.getComponent(), "Console",
IconLoader.getIcon("/debugger/console.png"),
console.getPreferredFocusableComponent());
@@ -0,0 +1,50 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.Topic;
/**
* @author yole
*/
public class PowerSaveMode {
private boolean myEnabled = false;
private final MessageBus myBus;
public PowerSaveMode(MessageBus bus) {
myBus = bus;
}
public static boolean isEnabled() {
return ServiceManager.getService(PowerSaveMode.class).myEnabled;
}
public static void setEnabled(boolean value) {
final PowerSaveMode instance = ServiceManager.getService(PowerSaveMode.class);
if (instance.myEnabled != value) {
instance.myEnabled = value;
instance.myBus.syncPublisher(TOPIC).powerSaveStateChanged();
}
}
public interface Listener {
void powerSaveStateChanged();
}
public static Topic<Listener> TOPIC = Topic.create("PowerSaveMode.Listener", Listener.class);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.actions;
import com.intellij.ide.PowerSaveMode;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.DumbAware;
/**
* @author yole
*/
public class TogglePowerSaveAction extends ToggleAction implements DumbAware {
@Override
public boolean isSelected(AnActionEvent e) {
return PowerSaveMode.isEnabled();
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
PowerSaveMode.setEnabled(state);
}
}
@@ -65,6 +65,7 @@ public final class CustomFileTypeLexer extends AbstractCustomLexer {
tokenParsers.add(multilineCommentParser);
}
tokenParsers.add(numberParser);
tokenParsers.add(new PunctuationParser());
if (hexNumberParser != null) {
tokenParsers.add(hexNumberParser);
}
@@ -42,8 +42,10 @@ class CustomFileTypeBraceMatcher implements BraceMatcher {
}
public boolean isRBraceToken(HighlighterIterator iterator, CharSequence fileText, FileType fileType) {
final IElementType tokenType = iterator.getTokenType();
return isRBraceToken(iterator.getTokenType());
}
private static boolean isRBraceToken(IElementType tokenType) {
return tokenType == CustomHighlighterTokenType.R_BRACKET ||
tokenType == CustomHighlighterTokenType.R_PARENTH ||
tokenType == CustomHighlighterTokenType.R_BRACE;
@@ -80,7 +82,9 @@ class CustomFileTypeBraceMatcher implements BraceMatcher {
}
public boolean isPairedBracesAllowedBeforeType(@NotNull final IElementType lbraceType, @Nullable final IElementType contextType) {
return contextType == CustomHighlighterTokenType.WHITESPACE;
return contextType == CustomHighlighterTokenType.PUNCTUATION ||
contextType == CustomHighlighterTokenType.WHITESPACE ||
isRBraceToken(contextType);
}
public int getCodeConstructStart(final PsiFile file, final int openingBraceOffset) {
@@ -0,0 +1,39 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.highlighter.custom.tokens;
import com.intellij.psi.CustomHighlighterTokenType;
/**
* @author peter
*/
public class PunctuationParser extends BaseTokenParser {
@Override
public boolean hasToken(int position) {
final char c = myBuffer.charAt(position);
if (".,:;".indexOf(c) >= 0) {
myTokenInfo.updateData(position, position+1, CustomHighlighterTokenType.PUNCTUATION);
return true;
}
return false;
}
@Override
public int getSmartUpdateShift() {
return 0;
}
}
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.impl.HectorComponent;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil;
import com.intellij.ide.DataManager;
import com.intellij.ide.PowerSaveMode;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
@@ -38,6 +39,7 @@ import com.intellij.psi.PsiManager;
import com.intellij.ui.UIBundle;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Consumer;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -57,7 +59,8 @@ public class TogglePopupHintsPanel implements StatusBarWidget, StatusBarWidget.I
public TogglePopupHintsPanel(@NotNull final Project project) {
myCurrentIcon = EMPTY_ICON;
project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() {
final MessageBusConnection connection = project.getMessageBus().connect();
connection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() {
@Override
public void selectionChanged(FileEditorManagerEvent event) {
updateStatus();
@@ -68,6 +71,12 @@ public class TogglePopupHintsPanel implements StatusBarWidget, StatusBarWidget.I
updateStatus();
}
});
connection.subscribe(PowerSaveMode.TOPIC, new PowerSaveMode.Listener() {
@Override
public void powerSaveStateChanged() {
updateStatus();
}
});
}
public void dispose() {
@@ -130,13 +139,21 @@ public class TogglePopupHintsPanel implements StatusBarWidget, StatusBarWidget.I
private void updateStatus(PsiFile file) {
if (isStateChangeable(file)) {
if (HighlightLevelUtil.shouldInspect(file)) {
if (PowerSaveMode.isEnabled()) {
myCurrentIcon = EMPTY_ICON;
myToolTipText = "Code analysis is disabled in power save mode. ";
}
else if (HighlightLevelUtil.shouldInspect(file)) {
myCurrentIcon = INSPECTIONS_ICON;
myToolTipText = "Current inspection profile: " + InspectionProjectProfileManager.getInstance(file.getProject()).getInspectionProfile().getName() + ". ";
} else if (HighlightLevelUtil.shouldHighlight(file)) {
myToolTipText = "Current inspection profile: " +
InspectionProjectProfileManager.getInstance(file.getProject()).getInspectionProfile().getName() +
". ";
}
else if (HighlightLevelUtil.shouldHighlight(file)) {
myCurrentIcon = SYNTAX_ONLY_ICON;
myToolTipText = "Highlighting level is: Syntax. ";
} else {
myToolTipText = "Highlighting level is: Syntax. ";
}
else {
myCurrentIcon = INSPECTIONS_OFF_ICON;
myToolTipText = "Inspections are off. ";
}
@@ -31,6 +31,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
@@ -487,34 +488,62 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
myManager.getCacheManager().processFilesWithWord(processor, word, UsageSearchContext.IN_STRINGS, scope, true);
}
public boolean processRequests(@NotNull SearchRequestCollector request, Processor<PsiReference> processor) {
final MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles = new MultiMap<Set<IdIndexEntry>, PsiSearchRequest>();
final List<Processor<Processor<PsiReference>>> customs = new ArrayList<Processor<Processor<PsiReference>>>();
distributePrimitives(request, singles, customs);
if (!processRequestsOptimized(singles, processor)) {
return false;
private static class RequestWithProcessor extends Pair<PsiSearchRequest, Processor<PsiReference>> {
private RequestWithProcessor(PsiSearchRequest first, Processor<PsiReference> second) {
super(first, second);
}
for (Processor<Processor<PsiReference>> custom : customs) {
if (!custom.process(processor)) {
return false;
}
}
return true;
}
private boolean processRequestsOptimized(MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles, final Processor<PsiReference> consumer) {
public boolean processRequests(@NotNull SearchRequestCollector collector, Processor<PsiReference> processor) {
Map<SearchRequestCollector, Processor<PsiReference>> collectors = new HashMap<SearchRequestCollector, Processor<PsiReference>>();
collectors.put(collector, processor);
appendCollectorsFromQueryRequests(collectors);
do {
final MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles = new MultiMap<Set<IdIndexEntry>, RequestWithProcessor>();
final List<Computable<Boolean>> customs = new ArrayList<Computable<Boolean>>();
distributePrimitives(collectors, singles, customs);
if (!processRequestsOptimized(singles)) {
return false;
}
for (Computable<Boolean> custom : customs) {
if (!custom.compute()) {
return false;
}
}
} while (appendCollectorsFromQueryRequests(collectors));
return true;
}
private static boolean appendCollectorsFromQueryRequests(Map<SearchRequestCollector, Processor<PsiReference>> collectors) {
boolean changed = false;
LinkedList<SearchRequestCollector> queue = new LinkedList<SearchRequestCollector>(collectors.keySet());
while (!queue.isEmpty()) {
final SearchRequestCollector each = queue.removeFirst();
for (QuerySearchRequest request : each.takeQueryRequests()) {
request.runQuery();
collectors.put(request.collector, request.processor);
queue.addLast(request.collector);
changed = true;
}
}
return changed;
}
private boolean processRequestsOptimized(MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles) {
if (singles.isEmpty()) {
return true;
}
if (singles.size() == 1) {
final Collection<PsiSearchRequest> requests = singles.get(singles.keySet().iterator().next());
final Collection<RequestWithProcessor> requests = singles.get(singles.keySet().iterator().next());
if (requests.size() == 1) {
return processSingleRequest(requests.iterator().next(), consumer);
final RequestWithProcessor theOnly = requests.iterator().next();
return processSingleRequest(theOnly.first, theOnly.second);
}
}
@@ -524,13 +553,17 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
progress.setText(PsiBundle.message("psi.scanning.files.progress"));
}
final MultiMap<VirtualFile, PsiSearchRequest> candidateFiles = collectFiles(singles);
final MultiMap<VirtualFile, RequestWithProcessor> candidateFiles = collectFiles(singles);
final Map<PsiSearchRequest, StringSearcher> searchers = new HashMap<PsiSearchRequest, StringSearcher>();
if (candidateFiles.isEmpty()) {
return true;
}
final Map<RequestWithProcessor, StringSearcher> searchers = new HashMap<RequestWithProcessor, StringSearcher>();
final Set<String> allWords = new TreeSet<String>();
for (PsiSearchRequest singleRequest : candidateFiles.values()) {
searchers.put(singleRequest, new StringSearcher(singleRequest.word, singleRequest.caseSensitive, true));
allWords.add(singleRequest.word);
for (RequestWithProcessor singleRequest : candidateFiles.values()) {
searchers.put(singleRequest, new StringSearcher(singleRequest.first.word, singleRequest.first.caseSensitive, true));
allWords.add(singleRequest.first.word);
}
if (progress != null) {
@@ -540,9 +573,9 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
return processPsiFileRoots(progress, new ArrayList<VirtualFile>(candidateFiles.keySet()), new Processor<PsiElement>() {
public boolean process(PsiElement psiRoot) {
final VirtualFile vfile = psiRoot.getContainingFile().getVirtualFile();
for (final PsiSearchRequest singleRequest : candidateFiles.get(vfile)) {
for (final RequestWithProcessor singleRequest : candidateFiles.get(vfile)) {
StringSearcher searcher = searchers.get(singleRequest);
if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest, consumer), psiRoot, searcher, false, progress)) {
if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest.first, singleRequest.second), psiRoot, searcher, false, progress)) {
return false;
}
}
@@ -565,18 +598,18 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
};
}
private MultiMap<VirtualFile, PsiSearchRequest> collectFiles(MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles) {
private MultiMap<VirtualFile, RequestWithProcessor> collectFiles(MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles) {
final ProjectFileIndex index = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex();
final MultiMap<VirtualFile, PsiSearchRequest> result = new MultiMap<VirtualFile, PsiSearchRequest>();
final MultiMap<VirtualFile, RequestWithProcessor> result = new MultiMap<VirtualFile, RequestWithProcessor>();
for (Set<IdIndexEntry> key : singles.keySet()) {
final Collection<PsiSearchRequest> data = singles.get(key);
final Collection<RequestWithProcessor> data = singles.get(key);
GlobalSearchScope commonScope = uniteScopes(data);
MultiMap<VirtualFile, PsiSearchRequest> intersection = null;
MultiMap<VirtualFile, RequestWithProcessor> intersection = null;
boolean first = true;
for (IdIndexEntry entry : key) {
final MultiMap<VirtualFile, PsiSearchRequest> local = findFilesWithIndexEntry(entry, index, data, commonScope);
final MultiMap<VirtualFile, RequestWithProcessor> local = findFilesWithIndexEntry(entry, index, data, commonScope);
if (first) {
intersection = local;
first = false;
@@ -593,31 +626,34 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
return result;
}
private static GlobalSearchScope uniteScopes(Collection<PsiSearchRequest> requests) {
private static GlobalSearchScope uniteScopes(Collection<RequestWithProcessor> requests) {
GlobalSearchScope commonScope = null;
for (PsiSearchRequest r : requests) {
final GlobalSearchScope scope = (GlobalSearchScope)r.searchScope;
for (RequestWithProcessor r : requests) {
final GlobalSearchScope scope = (GlobalSearchScope)r.first.searchScope;
commonScope = commonScope == null ? scope : commonScope.uniteWith(scope);
}
assert commonScope != null;
return commonScope;
}
private static MultiMap<VirtualFile, PsiSearchRequest> findFilesWithIndexEntry(final IdIndexEntry entry,
private static MultiMap<VirtualFile, RequestWithProcessor> findFilesWithIndexEntry(final IdIndexEntry entry,
final ProjectFileIndex index,
final Collection<PsiSearchRequest> data,
final Collection<RequestWithProcessor> data,
final GlobalSearchScope commonScope) {
final MultiMap<VirtualFile, PsiSearchRequest> local = new MultiMap<VirtualFile, PsiSearchRequest>();
final MultiMap<VirtualFile, RequestWithProcessor> local = new MultiMap<VirtualFile, RequestWithProcessor>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
ProgressManager.checkCanceled();
FileBasedIndex.getInstance().processValues(IdIndex.NAME, entry, null, new FileBasedIndex.ValueProcessor<Integer>() {
public boolean process(VirtualFile file, Integer value) {
ProgressManager.checkCanceled();
if (!IndexCacheManagerImpl.shouldBeFound(file, index)) {
return true;
}
int mask = value.intValue();
for (PsiSearchRequest single : data) {
if ((mask & single.searchContext) != 0 && ((GlobalSearchScope)single.searchScope).contains(file)) {
for (RequestWithProcessor single : data) {
final PsiSearchRequest request = single.first;
if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) {
local.putValue(file, single);
}
}
@@ -630,27 +666,38 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
return local;
}
private void distributePrimitives(SearchRequestCollector request,
MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles,
List<Processor<Processor<PsiReference>>> customs) {
for (final PsiSearchRequest primitive : request.getSearchRequests()) {
final SearchScope scope = primitive.searchScope;
if (scope instanceof LocalSearchScope) {
customs.add(new Processor<Processor<PsiReference>>() {
public boolean process(Processor<PsiReference> processor) {
return processSingleRequest(primitive, processor);
private void distributePrimitives(final Map<SearchRequestCollector, Processor<PsiReference>> collectors,
MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles,
List<Computable<Boolean>> customs) {
for (final SearchRequestCollector collector : collectors.keySet()) {
final Processor<PsiReference> processor = collectors.get(collector);
for (final PsiSearchRequest primitive : collector.takeSearchRequests()) {
final SearchScope scope = primitive.searchScope;
if (scope instanceof LocalSearchScope) {
customs.add(new Computable<Boolean>() {
@Override
public Boolean compute() {
return processSingleRequest(primitive, processor);
}
});
} else {
final List<String> words = StringUtil.getWordsIn(primitive.word);
final Set<IdIndexEntry> key = new HashSet<IdIndexEntry>(words.size() * 2);
for (String word : words) {
key.add(new IdIndexEntry(word, primitive.caseSensitive));
}
singles.putValue(key, new RequestWithProcessor(primitive, processor));
}
}
for (final Processor<Processor<PsiReference>> customAction : collector.takeCustomSearchActions()) {
customs.add(new Computable<Boolean>() {
@Override
public Boolean compute() {
return customAction.process(processor);
}
});
} else {
final List<String> words = StringUtil.getWordsIn(primitive.word);
final Set<IdIndexEntry> key = new HashSet<IdIndexEntry>(words.size() * 2);
for (String word : words) {
key.add(new IdIndexEntry(word, primitive.caseSensitive));
}
singles.putValue(key, primitive);
}
}
customs.addAll(request.getCustomSearchActions());
}
private boolean processSingleRequest(PsiSearchRequest single, Processor<PsiReference> consumer) {
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.util.proximity;
import com.intellij.openapi.util.NullableLazyKey;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.ProximityLocation;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.NullableFunction;
import org.jetbrains.annotations.NotNull;
/**
* NOTE: This class is only registered in platform-based IDEs. In IDEA, SamePackageWeigher is used instead.
*
* @author yole
*/
public class SameDirectoryWeigher extends ProximityWeigher {
private static final NullableLazyKey<PsiDirectory, ProximityLocation>
PLACE_DIRECTORY = NullableLazyKey.create("placeDirectory", new NullableFunction<ProximityLocation, PsiDirectory>() {
@Override
public PsiDirectory fun(ProximityLocation location) {
return PsiTreeUtil.getParentOfType(location.getPosition(), PsiDirectory.class, false);
}
});
public Comparable weigh(@NotNull final PsiElement element, final ProximityLocation location) {
final PsiDirectory placeDirectory = PLACE_DIRECTORY.getValue(location);
if (placeDirectory == null) {
return false;
}
return placeDirectory.equals(PsiTreeUtil.getParentOfType(element, PsiDirectory.class, false));
}
}
@@ -1662,10 +1662,20 @@ public class AbstractTreeUi {
return result;
}
if (myResettingToReadyNow.get()) {
getReady(this).notify(result);
return result;
}
myResettingToReadyNow.set(true);
invokeLaterIfNeeded(new Runnable() {
public void run() {
if (!myResettingToReadyNow.get()) {
result.setDone();
return;
}
Progressive[] progressives = myBatchIndicators.keySet().toArray(new Progressive[myBatchIndicators.size()]);
for (Progressive each : progressives) {
myBatchIndicators.remove(each).cancel();
@@ -1790,6 +1800,10 @@ public class AbstractTreeUi {
return isReady(false);
}
public boolean isCancelledReady() {
return isReady(false) && myCancelledBuild.size() > 0;
}
public boolean isReady(boolean attempt) {
Boolean ready = _isReady(attempt);
return ready != null && ready.booleanValue();
@@ -1864,6 +1878,11 @@ public class AbstractTreeUi {
try {
try {
myYeildingPasses.remove(pass);
if (!canInitiateNewActivity()) {
throw new ProcessCanceledException();
}
runnable.run();
}
finally {
@@ -15,10 +15,7 @@
*/
package com.intellij.codeInsight.hint;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.DocumentFragment;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.FoldingModelEx;
import com.intellij.openapi.util.TextRange;
@@ -51,7 +48,10 @@ public class DocumentFragmentTooltipRenderer implements TooltipRenderer {
JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
p = editor.logicalPositionToXY(new LogicalPosition(startLine, 0));
// There is a possible case that collapsed folding region is soft wrapped, hence, we need to anchor
// not logical but visual line start.
VisualPosition visual = editor.offsetToVisualPosition(startOffset);
p = editor.visualPositionToXY(visual);
p = SwingUtilities.convertPoint(
((EditorEx)editor).getGutterComponentEx(),
p,
@@ -341,11 +341,10 @@ public class EditorUtil {
for (int i = start; i < end; i++) {
char c = text.charAt(i);
prevX = x;
if (c == '\t') {
x = nextTabStop(x, editor);
}
else {
x += charWidth(c, Font.PLAIN, editor);
switch (c) {
case '\t': x = nextTabStop(x, editor); break;
case '\n': x = result = 0; break;
default: x += charWidth(c, Font.PLAIN, editor);
}
result += columnsNumber(c, x, prevX, getSpaceWidth(Font.PLAIN, editor));
}
@@ -1055,7 +1055,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
if (logLine == 0) {
if (logLine <= 0) {
lineStartOffset = 0;
}
else if (lineStartOffset < 0) {
@@ -2700,6 +2700,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
if (column < 0) column = 0;
line = Math.min(line, myDocument.getLineCount() - 1);
LogicalPosition softWrapUnawareResult = new LogicalPosition(line, column);
return mySoftWrapModel.adjustLogicalPosition(softWrapUnawareResult, visiblePos);
@@ -4797,7 +4798,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
// I.e. we shouldn't use widths of the lines that are not shown for max width calculation because previous widths are calculated
// for another visible area width.
int startToUse = 0;
int endToUse = lineCount;
int endToUse = Math.min(lineCount, myLineWidths.size());
if (getSoftWrapModel().isSoftWrappingEnabled()) {
Rectangle visibleArea = getScrollingModel().getVisibleArea();
startToUse = xyToLogicalPosition(visibleArea.getLocation()).line + 1;
@@ -583,10 +583,12 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
private class MyErrorPanel extends ButtonlessScrollBarUI implements MouseMotionListener, MouseListener {
private PopupHandler myHandler;
private ErrorStripeButton myErrorStripeButton;
@Override
protected JButton createDecreaseButton(int orientation) {
return new ErrorStripeButton();
myErrorStripeButton = new ErrorStripeButton();
return myErrorStripeButton;
}
@Override
@@ -594,12 +596,16 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
super.installListeners();
scrollbar.addMouseMotionListener(this);
scrollbar.addMouseListener(this);
myErrorStripeButton.addMouseMotionListener(this);
myErrorStripeButton.addMouseListener(this);
}
@Override
protected void uninstallListeners() {
scrollbar.removeMouseMotionListener(this);
scrollbar.removeMouseListener(this);
myErrorStripeButton.removeMouseMotionListener(this);
myErrorStripeButton.removeMouseListener(this);
super.uninstallListeners();
}
@@ -735,10 +741,12 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
public void setPopupHandler(final PopupHandler handler) {
if (myHandler != null) {
scrollbar.removeMouseListener(myHandler);
myErrorStripeButton.removeMouseListener(myHandler);
}
myHandler = handler;
scrollbar.addMouseListener(handler);
myErrorStripeButton.addMouseListener(myHandler);
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.impl.EditorTextRepresentationHelper;
import com.intellij.openapi.editor.impl.IterationState;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -36,6 +37,8 @@ import java.util.List;
*/
public class SoftWrapDataMapper {
private static final VisualPosition DUMMY_VISUAL = new VisualPosition(Integer.MAX_VALUE, Integer.MAX_VALUE);
private final CharBuffer myCharBuffer = CharBuffer.allocate(1);
private final EditorTextRepresentationHelper myTextRepresentationHelper;
@@ -67,6 +70,17 @@ public class SoftWrapDataMapper {
@NotNull
public LogicalPosition adjustLogicalPosition(@NotNull LogicalPosition defaultLogical, @NotNull VisualPosition visual) {
try {
return doAdjustLogicalPosition(defaultLogical, visual);
}
finally {
myFontTypeProvider.cleanup();
}
}
@SuppressWarnings({"AssignmentToForLoopParameter"})
@NotNull
private LogicalPosition doAdjustLogicalPosition(@NotNull LogicalPosition defaultLogical, @NotNull VisualPosition visual) {
Document document = myEditor.getDocument();
int maxOffset = document.getLineEndOffset(Math.min(defaultLogical.line, document.getLineCount() - 1));
@@ -86,7 +100,7 @@ public class SoftWrapDataMapper {
int max = Math.min(softWraps.size(), endIndex);
for (; i < max; i++) {
TextChange softWrap = softWraps.get(i);
if (foldingModel.isOffsetCollapsed(softWrap.getStart())) {
if (!isVisible(softWrap)) {
continue;
}
@@ -97,10 +111,11 @@ public class SoftWrapDataMapper {
if (visualLineBeforeSoftWrapAppliance > visual.line) {
softWrapLinesBeforeCurrentLogicalLine += softWrapLinesOnCurrentLogicalLine;
int logicalLine = defaultLogical.line - softWrapLinesBeforeCurrentLogicalLine;
LogicalPosition foldingUnawarePosition = new LogicalPosition(
logicalLine, defaultLogical.column, softWrapLinesBeforeCurrentLogicalLine, 0, 0, 0, 0
return new LogicalPosition(
logicalLine, defaultLogical.column, softWrapLinesBeforeCurrentLogicalLine, 0, 0,
getFoldedLinesBefore(document.getLineStartOffset(logicalLine)),
visual.column - defaultLogical.column
);
return adjustFoldingData(foldingModel, foldingUnawarePosition);
}
if (lastSoftWrapLogicalLine >= 0 && lastSoftWrapLogicalLine != softWrapLine) {
@@ -115,24 +130,29 @@ public class SoftWrapDataMapper {
continue;
}
int startLineOffset = document.getLineStartOffset(softWrapLine);
int endLineOffset = document.getLineEndOffset(softWrapLine);
FoldRegion region = foldingModel.getCollapsedRegionAtOffset(endLineOffset);
while (region != null) {
int line = document.getLineNumber(region.getEndOffset());
endLineOffset = document.getLineEndOffset(line);
region = foldingModel.getCollapsedRegionAtOffset(endLineOffset);
}
CharSequence documentText = document.getCharsSequence();
// If we're here that means that current soft wrap affects logical line that is matched to the given visual line.
// We iterate from the logical line start then in order to calculate resulting logical position.
Context context = new Context(
defaultLogical, visual, softWrapLinesBeforeCurrentLogicalLine, softWrapLinesOnCurrentLogicalLine,
visualLineBeforeSoftWrapAppliance, foldingModel
visual, softWrapLine, softWrapLinesBeforeCurrentLogicalLine, softWrapLinesOnCurrentLogicalLine,
visualLineBeforeSoftWrapAppliance, getFoldedLinesBefore(startLineOffset)
);
int startLineOffset = document.getLineStartOffset(softWrapLine);
int endLineOffset = document.getLineEndOffset(softWrapLine);
CharSequence documentText = document.getCharsSequence();
myFontTypeProvider.init(startLineOffset);
context.fontType = myFontTypeProvider.getFontType(startLineOffset);
for (int j = startLineOffset; j < endLineOffset; j++) {
// Process soft wrap at the current offset if any.
TextChange softWrapToProcess = myStorage.getSoftWrap(j);
if (softWrapToProcess != null) {
if (softWrapToProcess != null && isVisible(softWrapToProcess)) {
context.beforeSoftWrap();
if (j >= softWrap.getStart()) {
CharSequence softWrapText = softWrapToProcess.getText();
@@ -146,7 +166,16 @@ public class SoftWrapDataMapper {
context.afterSoftWrap();
}
context.fontType = myFontTypeProvider.getFontType(startLineOffset);
context.fontType = myFontTypeProvider.getFontType(j);
FoldRegion foldRegion = foldingModel.getCollapsedRegionAtOffset(j);
if (foldRegion != null) {
LogicalPosition result = context.onCollapsedFolding(foldRegion);
if (result != null) {
return result;
}
j = foldRegion.getEndOffset();
}
// Process document symbol.
LogicalPosition result = context.onNonSoftWrapSymbol(documentText.charAt(j));
@@ -154,27 +183,25 @@ public class SoftWrapDataMapper {
return result;
}
}
myFontTypeProvider.cleanup();
// If we are here that means that target visual position is located at virtual space after the line end.
int logicalLine = defaultLogical.line - softWrapLinesBeforeCurrentLogicalLine
- context.softWrapLinesOnCurrentLineBeforeTargetSoftWrap - context.targetSoftWrapLines;
int logicalColumn = context.symbolsOnCurrentLogicalLine + visual.column - context.symbolsOnCurrentVisualLine;
int softWrapColumnDiff = visual.column - logicalColumn;
LogicalPosition foldingUnawarePosition = new LogicalPosition(
logicalLine, logicalColumn, softWrapLinesBeforeCurrentLogicalLine,
context.softWrapLinesOnCurrentLineBeforeTargetSoftWrap + context.targetSoftWrapLines, softWrapColumnDiff, 0, 0
);
return adjustFoldingData(foldingModel, foldingUnawarePosition);
context.logicalColumn += visual.column - context.visualColumn;
return context.build();
}
// If we are here that means that there is no soft wrap on a logical line that corresponds to the target visual line.
softWrapLinesBeforeCurrentLogicalLine += softWrapLinesOnCurrentLogicalLine;
int logicalLine = defaultLogical.line - softWrapLinesBeforeCurrentLogicalLine;
LogicalPosition foldingUnaware = new LogicalPosition(
logicalLine, defaultLogical.column, softWrapLinesBeforeCurrentLogicalLine, 0, 0, 0, 0
// There is a possible case that we can't count on given default logical position - e.g. if given visual position line
// is more than total document lines count.
if (logicalLine < 0) {
logicalLine = Math.min(lastSoftWrapLogicalLine + 1, document.getLineCount() - 1);
}
int foldedLines = getFoldedLinesBefore(document.getLineStartOffset(logicalLine));
int foldingColumnDiff = visual.column - defaultLogical.column;
return new LogicalPosition(
logicalLine, defaultLogical.column, softWrapLinesBeforeCurrentLogicalLine, 0, 0, foldedLines, foldingColumnDiff
);
return adjustFoldingData(foldingModel, foldingUnaware);
}
@NotNull
@@ -202,7 +229,6 @@ public class SoftWrapDataMapper {
int lineDiff = 0;
int column = -1;
FoldingModel foldingModel = myEditor.getFoldingModel();
int targetLogicalLineStartOffset = myEditor.logicalPositionToOffset(new LogicalPosition(logical.line, 0));
for (int i = endIndex; i >= 0; i--) {
TextChange softWrap = softWraps.get(i);
@@ -211,7 +237,7 @@ public class SoftWrapDataMapper {
continue;
}
if (foldingModel.isOffsetCollapsed(softWrap.getStart())) {
if (!isVisible(softWrap)) {
continue;
}
@@ -237,120 +263,161 @@ public class SoftWrapDataMapper {
return new VisualPosition(visual.line + lineDiff, columnToUse);
}
@SuppressWarnings({"AssignmentToForLoopParameter"})
public LogicalPosition offsetToLogicalPosition(int offset) {
try {
return doOffsetToLogicalPosition(offset);
}
finally {
myFontTypeProvider.cleanup();
}
}
@SuppressWarnings({"AssignmentToForLoopParameter"})
private LogicalPosition doOffsetToLogicalPosition(int offset) {
FoldingModel foldingModel = myEditor.getFoldingModel();
Document document = myEditor.getDocument();
CharSequence chars = document.getCharsSequence();
CharSequence text = document.getCharsSequence();
int line = document.getLineNumber(offset);
int lineStartOffset = document.getLineStartOffset(line);
FoldRegion region = foldingModel.getCollapsedRegionAtOffset(lineStartOffset);
while (region != null && region.getStartOffset() != lineStartOffset) {
line = document.getLineNumber(region.getStartOffset());
lineStartOffset = document.getLineStartOffset(line);
region = foldingModel.getCollapsedRegionAtOffset(lineStartOffset);
}
int targetLine = document.getLineNumber(offset);
int targetLineStartOffset = document.getLineStartOffset(targetLine);
Context context = new Context(line, getSoftWrapIntroducedLinesBefore(lineStartOffset), getFoldedLinesBefore(lineStartOffset));
myFontTypeProvider.init(lineStartOffset);
context.fontType = myFontTypeProvider.getFontType(lineStartOffset);
for (int i = lineStartOffset; i <= offset; i++) {
TextChangeImpl softWrap = myStorage.getSoftWrap(i);
if (softWrap != null) {
context.beforeSoftWrap();
CharSequence softWrapText = softWrap.getText();
for (int k = 0; k < softWrapText.length(); k++) {
context.onSoftWrapSymbol(softWrapText.charAt(k));
}
context.afterSoftWrap();
}
int softWrapIntroducedLinesBefore = 0;
int softWrapsOnCurrentLogicalLine = 0;
int symbolsOnCurrentLogicalLine = 0;
int symbolsOnCurrentVisibleLine = 0;
List<TextChangeImpl> softWraps = myStorage.getSoftWraps();
if (i == offset) {
// We want to count soft wrap that is registered at target offset if any but not exceeding document symbols.
break;
}
// Retrieve information about logical position that is soft-wraps unaware.
LogicalPosition rawLineStartLogicalPosition = myEditor.offsetToLogicalPosition(targetLineStartOffset);
region = foldingModel.getCollapsedRegionAtOffset(i);
if (region != null) {
processFoldRegion(context, region, offset);
if (offset <= region.getEndOffset()) {
break;
}
i = region.getEndOffset();
}
context.fontType = myFontTypeProvider.getFontType(i);
context.onNonSoftWrapSymbol(text.charAt(i));
}
return new LogicalPosition(
context.logicalLine,
context.logicalColumn,
context.softWrapLinesBefore,
context.targetSoftWrapLines,
context.softWrapColumnDiff,
getFoldedLinesBefore(offset),
context.foldingColumnDiff
);
}
/**
* Processes given collapsed fold region assuming that we need to stop at a target offset.
* <p/>
* Processing result is updated state of the given context object.
*
* @param context processing data holder
* @param region collapsed fold region to process
* @param offset target stop offset
*/
@SuppressWarnings({"AssignmentToForLoopParameter"})
private void processFoldRegion(Context context, FoldRegion region, int offset) {
CharSequence text = myEditor.getDocument().getCharsSequence();
int max = Math.min(offset, region.getEndOffset());
boolean multilineFolding = false;
for (int i = region.getStartOffset(); i < max;) {
int lineFeedOffset = CharArrayUtil.shiftForwardUntil(text, i, "\n");
if (lineFeedOffset < max) {
context.softWrapLinesBefore += context.targetSoftWrapLines;
context.targetSoftWrapLines = 0;
context.softWrapColumnDiff = 0;
context.foldedLines++;
context.logicalColumn = 0;
context.foldingColumnDiff = context.visualColumn;
context.logicalLine++;
i = lineFeedOffset + 1;
multilineFolding = true;
}
else {
if (multilineFolding) {
context.logicalColumn = myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, i, max, 0);
context.foldingColumnDiff = context.visualColumn - context.logicalColumn;
break;
}
else {
int foldedColumns = myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, region.getStartOffset(), max, context.x);
context.logicalColumn += foldedColumns;
context.foldingColumnDiff -= foldedColumns;
if (offset >= region.getEndOffset()) {
context.foldingColumnDiff += region.getPlaceholderText().length();
}
return;
}
}
}
if (offset >= region.getEndOffset()) {
int foldPlaceholderColumns = region.getPlaceholderText().length();
context.visualColumn += foldPlaceholderColumns;
context.foldingColumnDiff += foldPlaceholderColumns;
context.x += foldPlaceholderColumns * myTextRepresentationHelper.charWidth(' ', context.x, Font.PLAIN);
}
}
/**
* Allows to answer how many soft wrap-introduced visual lines are located before the given offset.
*
* @param offset target offset
* @return number of soft wrap-introduced visual lines are located before the given offset
*/
private int getSoftWrapIntroducedLinesBefore(int offset) {
int result = 0;
List<? extends TextChange> softWraps = myStorage.getSoftWraps();
// Calculate number of soft wrap-introduced lines before the line that holds target offset.
int index = myStorage.getSoftWrapIndex(targetLineStartOffset);
int index = myStorage.getSoftWrapIndex(offset);
if (index < 0) {
index = -index - 1;
}
int max = Math.min(index, softWraps.size());
for (int j = 0; j < max; j++) {
softWrapIntroducedLinesBefore += StringUtil.countNewLines(softWraps.get(j).getText());
}
FoldingModel foldingModel = myEditor.getFoldingModel();
// Return eagerly if there are no soft wraps before the target offset on a line that contains it.
if (max >= softWraps.size() || softWraps.get(max).getStart() > offset) {
int column = myTextRepresentationHelper.toVisualColumnSymbolsNumber(chars, targetLineStartOffset, offset, 0);
LogicalPosition foldingUnawarePosition = new LogicalPosition(
rawLineStartLogicalPosition.line, column, softWrapIntroducedLinesBefore, 0, 0, 0, 0
);
return adjustFoldingData(foldingModel, foldingUnawarePosition);
}
// Calculate number of lines and columns introduced by soft wrap located at the line that holds target offset if any.
// We add '1' here in order to correctly process situation when there is soft wrap at target offset (it impacts resulting logical
// position but document symbol at that offset should not be count).
max = Math.min(chars.length(), offset + 1);
int x = 0;
myFontTypeProvider.init(targetLineStartOffset);
int fontType = myFontTypeProvider.getFontType(targetLineStartOffset);
for (int i = targetLineStartOffset; i < max; i++) {
FoldRegion region = foldingModel.getCollapsedRegionAtOffset(i);
if (region != null) {
// Assuming that folded region placeholder doesn't contain line feed symbols.
i = region.getEndOffset();
symbolsOnCurrentVisibleLine += region.getPlaceholderText().length();
continue;
TextChange softWrap = softWraps.get(j);
if (isVisible(softWrap)) {
result += StringUtil.countNewLines(softWrap.getText());
}
TextChange softWrap = myStorage.getSoftWrap(i);
if (softWrap != null) {
CharSequence softWrapText = softWrap.getText();
for (int j = 0; j < softWrapText.length(); j++) {
if (softWrapText.charAt(j) == '\n') {
softWrapsOnCurrentLogicalLine++;
symbolsOnCurrentVisibleLine = 0;
x = 0;
}
else {
symbolsOnCurrentVisibleLine++;
x += myTextRepresentationHelper.charWidth(softWrapText.charAt(j), x, fontType);
}
}
symbolsOnCurrentVisibleLine++; // For 'after soft wrap' sign.
x += myPainter.getMinDrawingWidth(SoftWrapDrawingType.AFTER_SOFT_WRAP);
}
// We don't want to count symbol at target offset.
if (i == offset) {
break;
}
fontType = myFontTypeProvider.getFontType(targetLineStartOffset);
// Assuming that no line feed is contained before target offset on a line that holds it.
int columnsForSymbol = toVisualColumnSymbolsNumber(chars.charAt(i), x);
symbolsOnCurrentLogicalLine += columnsForSymbol;
symbolsOnCurrentVisibleLine += columnsForSymbol;
x += myTextRepresentationHelper.charWidth(chars.charAt(i), x, fontType);
}
myFontTypeProvider.cleanup();
LogicalPosition foldingUnawarePosition = new LogicalPosition(
rawLineStartLogicalPosition.line, symbolsOnCurrentLogicalLine, softWrapIntroducedLinesBefore, softWrapsOnCurrentLogicalLine,
symbolsOnCurrentVisibleLine - symbolsOnCurrentLogicalLine, 0, 0
);
return adjustFoldingData(foldingModel, foldingUnawarePosition);
return result;
}
/**
* Builds folding-aware logical position on the basis of the given folding-unaware position and folding model
* Allows to answer how many folded lines are located before the logical line that contains given offset.
*
* @param foldingModel folding model to use for retrieving information about folding
* @param position folding-unaware logical position
* @return folding-aware logical position
* @param offset target offset
* @return number of folded lines are located before the logical line that contains given offset.
*/
private LogicalPosition adjustFoldingData(FoldingModel foldingModel, LogicalPosition position) {
int offset = myEditor.logicalPositionToOffset(position);
int foldedLines = 0;
int foldColumnDiff = 0;
int softWrapColumnDiff = position.softWrapColumnDiff;
private int getFoldedLinesBefore(int offset) {
Document document = myEditor.getDocument();
int targetLine = document.getLineNumber(offset);
int lastFoldEndLogicalLine = -1;
for (FoldRegion foldRegion : foldingModel.getAllFoldRegions()) {
if (foldRegion.getStartOffset() >= offset) {
int line = document.getLineNumber(offset);
int lineStartOffset = document.getLineStartOffset(line);
int result = 0;
for (FoldRegion foldRegion : myEditor.getFoldingModel().getAllFoldRegions()) {
if (foldRegion.getStartOffset() >= lineStartOffset) {
break;
}
@@ -360,99 +427,20 @@ public class SoftWrapDataMapper {
int foldingStartLine = document.getLineNumber(foldRegion.getStartOffset());
int foldingEndLine = document.getLineNumber(foldRegion.getEndOffset());
foldedLines += Math.min(targetLine, foldingEndLine) - foldingStartLine;
// Process situation when target offset is located inside the folded region.
if (offset >= foldRegion.getStartOffset()) {
if (offset < foldRegion.getEndOffset()) {
// Our purpose is to define folding data in order to point to the visual folding start.
int visualFoldingStartColumn = calculateVisualFoldingStartColumn(foldRegion);
int diff = visualFoldingStartColumn - position.column - softWrapColumnDiff;
if (lastFoldEndLogicalLine == foldingStartLine) {
foldColumnDiff += diff;
}
else {
foldColumnDiff = diff;
}
return new LogicalPosition(
position.line, position.column, position.softWrapLinesBeforeCurrentLogicalLine, position.softWrapLinesOnCurrentLogicalLine,
softWrapColumnDiff, foldedLines, foldColumnDiff
);
}
int diff = getFoldColumnDiff(foldRegion);
if (lastFoldEndLogicalLine == foldingStartLine) {
foldColumnDiff += diff;
}
else {
foldColumnDiff = diff;
}
lastFoldEndLogicalLine = foldingEndLine;
}
}
if (lastFoldEndLogicalLine != position.line) {
foldColumnDiff = 0;
}
return new LogicalPosition(
position.line, position.column, position.softWrapLinesBeforeCurrentLogicalLine, position.softWrapLinesOnCurrentLogicalLine,
softWrapColumnDiff, foldedLines, foldColumnDiff
);
}
private int getFoldColumnDiff(FoldRegion region) {
int visualFoldingStartColumn = calculateVisualFoldingStartColumn(region);
LogicalPosition foldEndLogical = myEditor.offsetToLogicalPosition(region.getEndOffset());
// Assuming that there is no tabulations symbols at placeholder text.
int foldingPlaceholderWidth = region.getPlaceholderText().length();
return visualFoldingStartColumn + foldingPlaceholderWidth - foldEndLogical.column;
}
private int calculateVisualFoldingStartColumn(FoldRegion region) {
Document document = myEditor.getDocument();
int foldingStartOffset = region.getStartOffset();
int logicalLine = document.getLineNumber(foldingStartOffset);
int logicalLineStartOffset = document.getLineStartOffset(logicalLine);
int softWrapIndex = myStorage.getSoftWrapIndex(logicalLineStartOffset);
if (softWrapIndex < 0) {
softWrapIndex = -softWrapIndex - 1;
}
List<TextChangeImpl> softWraps = myStorage.getSoftWraps();
int startOffsetOfVisualLineWithFoldingStart = logicalLineStartOffset;
int softWrapOffsetInColumns = 0;
for (; softWrapIndex < softWraps.size(); softWrapIndex++) {
TextChange softWrap = softWraps.get(softWrapIndex);
if (softWrap.getStart() >= foldingStartOffset) {
break;
}
startOffsetOfVisualLineWithFoldingStart = softWrap.getStart();
softWrapOffsetInColumns = numberOfSymbolsOnLastVisualLine(softWrap);
}
assert startOffsetOfVisualLineWithFoldingStart <= foldingStartOffset;
int x = softWrapOffsetInColumns * myTextRepresentationHelper.charWidth(' ', 0, Font.PLAIN);
return myTextRepresentationHelper.toVisualColumnSymbolsNumber(
document.getCharsSequence(), startOffsetOfVisualLineWithFoldingStart, foldingStartOffset, x
);
}
private static int numberOfSymbolsOnLastVisualLine(TextChange textChange) {
int result = 0;
for (int i = textChange.getText().length() - 1; i >= 0; i--) {
if (i == '\n') {
return result;
}
else {
result++;
}
result += Math.min(line, foldingEndLine) - foldingStartLine;
}
return result;
}
private boolean isVisible(TextChange softWrap) {
FoldingModel foldingModel = myEditor.getFoldingModel();
int start = softWrap.getStart();
// There is a possible case that folding region starts just after soft wrap, i.e. soft wrap and folding region share the
// same offset. However, soft wrap is shown, hence, we also check offset just before the target one.
return !foldingModel.isOffsetCollapsed(start) || !foldingModel.isOffsetCollapsed(start - 1);
}
private int toVisualColumnSymbolsNumber(char c, int x) {
myCharBuffer.clear();
myCharBuffer.put(c);
@@ -462,28 +450,36 @@ public class SoftWrapDataMapper {
private class Context {
public final FoldingModel foldingModel;
public final LogicalPosition softWrapUnawareLogicalPosition;
public final VisualPosition targetVisualPosition;
public final int softWrapLinesBefore;
public final int visualLineBeforeSoftWrapAppliance;
public final int softWrapLinesOnCurrentLineBeforeTargetSoftWrap;
public int logicalLine;
public int visualLine;
public int softWrapLinesBefore;
public int targetSoftWrapLines;
public int symbolsOnCurrentLogicalLine;
public int symbolsOnCurrentVisualLine;
public int softWrapColumnDiff;
public int logicalColumn;
public int visualColumn;
public int foldedLines;
public int foldingColumnDiff;
public int x;
public int fontType;
Context(LogicalPosition softWrapUnawareLogicalPosition, VisualPosition targetVisualPosition, int softWrapLinesBefore,
int softWrapLinesOnCurrentLineBeforeTargetSoftWrap, int visualLineBeforeSoftWrapAppliance, FoldingModel foldingModel)
Context(int logicalLine, int softWrapLinesBefore, int foldedLines) {
this(DUMMY_VISUAL, logicalLine, softWrapLinesBefore, 0, 0, foldedLines);
}
Context(VisualPosition targetVisualPosition, int logicalLine, int softWrapLinesBefore,
int softWrapLinesOnCurrentLineBeforeTargetSoftWrap, int visualLineBeforeSoftWrapAppliance, int foldedLines)
{
this.softWrapUnawareLogicalPosition = softWrapUnawareLogicalPosition;
this.targetVisualPosition = targetVisualPosition;
this.softWrapLinesBefore = softWrapLinesBefore;
this.softWrapLinesOnCurrentLineBeforeTargetSoftWrap = softWrapLinesOnCurrentLineBeforeTargetSoftWrap;
this.visualLineBeforeSoftWrapAppliance = visualLineBeforeSoftWrapAppliance;
this.foldingModel = foldingModel;
this.foldedLines = foldedLines;
this.logicalLine = logicalLine;
visualLine = visualLineBeforeSoftWrapAppliance + targetSoftWrapLines;
}
/**
@@ -498,19 +494,24 @@ public class SoftWrapDataMapper {
// Process line feed inside soft wrap.
if (c == '\n') {
if (targetVisualPosition.line == visualLineBeforeSoftWrapAppliance + targetSoftWrapLines) {
return build(targetVisualPosition.column - symbolsOnCurrentLogicalLine);
softWrapColumnDiff = targetVisualPosition.column - logicalColumn;
return build();
}
else {
x = 0;
softWrapColumnDiff = -logicalColumn;
targetSoftWrapLines++;
symbolsOnCurrentVisualLine = 0;
visualLine++;
visualColumn = 0;
return null;
}
}
softWrapColumnDiff++;
// Just update information about tracked symbols number if current visual line is too low.
if (targetVisualPosition.line > visualLineBeforeSoftWrapAppliance + targetSoftWrapLines) {
symbolsOnCurrentVisualLine += toVisualColumnSymbolsNumber(c, x);
visualColumn += toVisualColumnSymbolsNumber(c, x);
x += myTextRepresentationHelper.charWidth(c, x, fontType);
return null;
}
@@ -518,15 +519,15 @@ public class SoftWrapDataMapper {
// There is a possible case that, for example, target visual column is zero and it points to the soft-wrapped line,
// i.e. soft wrap are. We shouldn't count symbols then. Hence, we perform this preliminary examination with eager
// return if necessary.
if (targetVisualPosition.column <= symbolsOnCurrentVisualLine) {
if (targetVisualPosition.column <= visualColumn) {
return build();
}
// Process non-line feed inside soft wrap.
symbolsOnCurrentVisualLine++; // Don't expect tabulation to be used inside soft wrap text.
visualColumn++; // Don't expect tabulation to be used inside soft wrap text.
x += myTextRepresentationHelper.charWidth(c, x, fontType);
if (targetVisualPosition.column <= symbolsOnCurrentVisualLine) {
if (targetVisualPosition.column <= visualColumn) {
return build();
}
else {
@@ -540,7 +541,54 @@ public class SoftWrapDataMapper {
public void afterSoftWrap() {
x += myPainter.getMinDrawingWidth(SoftWrapDrawingType.AFTER_SOFT_WRAP);
symbolsOnCurrentVisualLine++;
visualColumn++;
softWrapColumnDiff++;
}
@SuppressWarnings({"AssignmentToForLoopParameter"})
@Nullable
public LogicalPosition onCollapsedFolding(FoldRegion region) {
int visualFoldingPlaceholderWidth = region.getPlaceholderText().length(); // Assuming that no tabs are used as placeholder
// Process situation when target visual position points to collapsed folding placeholder.
if (visualLine == targetVisualPosition.line && visualColumn + visualFoldingPlaceholderWidth > targetVisualPosition.column) {
return build();
}
// If control flow reaches this point that means that we should process whole folded region and update current object state.
CharSequence text = myEditor.getDocument().getCharsSequence();
boolean multiline = false;
for (int i = region.getStartOffset(); i < region.getEndOffset();) {
int lineFeedOffset = CharArrayUtil.shiftForwardUntil(text, i, "\n");
// Process multiline folded text.
if (lineFeedOffset < region.getEndOffset()) {
logicalLine++;
foldedLines++;
logicalColumn = 0;
softWrapLinesBefore += targetSoftWrapLines;
targetSoftWrapLines = 0;
softWrapColumnDiff = 0;
i = lineFeedOffset + 1;
multiline = true;
}
else {
if (multiline) {
logicalColumn = myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, i, region.getEndOffset(), 0);
}
else {
logicalColumn += myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, i, region.getEndOffset(), x);
}
foldingColumnDiff = visualColumn + visualFoldingPlaceholderWidth - logicalColumn - softWrapColumnDiff;
i = region.getEndOffset();
}
}
visualColumn += visualFoldingPlaceholderWidth;
x += visualFoldingPlaceholderWidth * myTextRepresentationHelper.charWidth(' ', x, Font.PLAIN);
if (visualLine == targetVisualPosition.line && visualColumn == targetVisualPosition.column) {
return build();
}
return null;
}
/**
@@ -560,31 +608,31 @@ public class SoftWrapDataMapper {
}
// Just update information about tracked symbols number if current visual line is too low.
if (targetVisualPosition.line > visualLineBeforeSoftWrapAppliance + targetSoftWrapLines) {
if (targetVisualPosition.line > visualLine) {
int columnsForSymbol = toVisualColumnSymbolsNumber(c, x);
symbolsOnCurrentVisualLine += columnsForSymbol;
symbolsOnCurrentLogicalLine += columnsForSymbol;
visualColumn += columnsForSymbol;
logicalColumn += columnsForSymbol;
x += myTextRepresentationHelper.charWidth(c, x, fontType);
return null;
}
// There is a possible case that, for example, target visual column is zero. We shouldn't count symbols then.
// Hence, we perform this preliminary examination with eager return if necessary.
if (targetVisualPosition.column <= symbolsOnCurrentVisualLine) {
if (targetVisualPosition.column <= visualColumn) {
return build();
}
int columnsForSymbol = toVisualColumnSymbolsNumber(c, x);
int diffInColumns = targetVisualPosition.column - symbolsOnCurrentVisualLine;
int diffInColumns = targetVisualPosition.column - visualColumn;
int incrementToUse = columnsForSymbol;
if (columnsForSymbol >= diffInColumns) {
incrementToUse = Math.min(columnsForSymbol, diffInColumns);
}
symbolsOnCurrentVisualLine += incrementToUse;
symbolsOnCurrentLogicalLine += incrementToUse;
visualColumn += incrementToUse;
logicalColumn += incrementToUse;
x += myTextRepresentationHelper.charWidth(c, x, fontType);
if (targetVisualPosition.column <= symbolsOnCurrentVisualLine) {
if (targetVisualPosition.column <= visualColumn) {
return build();
}
else {
@@ -593,22 +641,19 @@ public class SoftWrapDataMapper {
}
private LogicalPosition build() {
return build(symbolsOnCurrentVisualLine - symbolsOnCurrentLogicalLine);
return build(foldingColumnDiff);
}
private LogicalPosition build(int softWrapColumnDiff) {
int logicalLine = softWrapUnawareLogicalPosition.line - softWrapLinesBefore
- softWrapLinesOnCurrentLineBeforeTargetSoftWrap - targetSoftWrapLines;
LogicalPosition foldingUnawareResult = new LogicalPosition(
private LogicalPosition build(int foldingColumnDiff) {
return new LogicalPosition(
logicalLine,
symbolsOnCurrentLogicalLine,
logicalColumn,
softWrapLinesBefore,
softWrapLinesOnCurrentLineBeforeTargetSoftWrap + targetSoftWrapLines,
softWrapColumnDiff,
0,
0
foldedLines,
foldingColumnDiff
);
return adjustFoldingData(foldingModel, foldingUnawareResult);
}
}
@@ -394,6 +394,10 @@ abstract class BaseTreeTestCase<StructureElement> extends FlyIdeaTestCase {
}
void select(final Object[] elements, final boolean addToSelection) throws Exception {
select(elements, addToSelection, false);
}
void select(final Object[] elements, final boolean addToSelection, final boolean canBeInterrupted) throws Exception {
final Ref<Boolean> done = new Ref<Boolean>(false);
doAndWaitForBuilder(new Runnable() {
public void run() {
@@ -405,7 +409,7 @@ abstract class BaseTreeTestCase<StructureElement> extends FlyIdeaTestCase {
}
}, new Condition() {
public boolean value(Object o) {
return done.get();
return done.get() || (canBeInterrupted && getBuilder().getUi().isCancelledReady());
}
});
}
@@ -59,6 +59,43 @@ public class TreeUiTest extends AbstractTreeBuilderTest {
assertInterruption(Interruption.invokeCancel);
}
public void testDoubleCancelUpdate() throws Exception {
buildStructure(myRoot);
runAndInterrupt(new Runnable() {
@Override
public void run() {
try {
select(new Object[] {new NodeElement("openapi")}, false, true);
}
catch (Exception e) {
fail();
}
}
}, "getChildren", new NodeElement("intellij"), Interruption.invokeCancel);
select(new NodeElement("fabrique"), false);
assertTree("-/\n"
+ " -com\n"
+ " intellij\n"
+ " -jetbrains\n"
+ " +[fabrique]\n"
+ " +org\n"
+ " +xunit\n");
updateFromRoot();
assertTree("-/\n"
+ " -com\n"
+ " +intellij\n"
+ " -jetbrains\n"
+ " +[fabrique]\n"
+ " +org\n"
+ " +xunit\n");
}
public void testBatchUpdate() throws Exception {
buildStructure(myRoot);
@@ -1987,6 +2024,12 @@ public class TreeUiTest extends AbstractTreeBuilderTest {
//todo
}
@Override
public void testDoubleCancelUpdate() throws Exception {
// doesn't make sense in pass-through mode
}
@Override
public void testSelectWhenUpdatesArePending() throws Exception {
// doesn't make sense in pass-through mode
@@ -201,9 +201,9 @@ public class SoftWrapDataMapperTest {
String document =
"public class Test {\n" +
" public void foo(int[] data) {\n" +
" bar(data[0], data[1], data[2], data[3], <WRAP>\n" +
" </WRAP>data[4], data[5], data[6], <WRAP> \n" +
" </WRAP>data[7], data[8]); \n" +
" bar(data[0], <WRAP>\n" +
" </WRAP>data[1], <WRAP> \n" +
" </WRAP>data[2]); \n" +
" }\n" +
" public void bar(int ... i) {\n" +
" }\n" +
@@ -230,22 +230,52 @@ public class SoftWrapDataMapperTest {
test(document);
}
@Test
public void softWrappedSingleLineFolding() {
String document =
"class Test {<WRAP>\n" +
" </WRAP><FOLD>public void foo() {}</FOLD> \n" +
" \n" +
"}";
test(document);
}
@Test
public void softWrappedMultiLineLineFolding() {
String document =
"class Test {<WRAP>\n" +
" </WRAP><FOLD>public void foo() {\n" +
" }</FOLD> \n" +
"}";
test(document);
}
@Test
public void multipleFoldRegionsAfterSingleSoftWrap() {
String document =
"class Test {<WRAP>\n" +
" </WRAP><FOLD>public void foo() {\n" +
" }</FOLD> <FOLD>// comment</FOLD> \n" +
"}";
test(document);
}
@Test
public void softWrapAndFoldedLines() {
String document =
"public class Test {\n" +
" public void foo(int[] data) {\n" +
" bar(data[0], data[1], <WRAP>\n" +
" </WRAP>data[2], data[3], <WRAP> \n" +
" </WRAP>data[4], data[5], \n" +
" data[6], data[7], \n" +
" <FOLD>data[8], data[9], \n" +
" data[10], data[11], \n" +
" data[12], data[13], </FOLD>\n" +
" data[14], data[15], \n" +
" data[16], data[17], <WRAP> \n" +
" </WRAP>data[18], data[19], <WRAP> \n" +
" </WRAP>data[20], data[21]); \n" +
" bar(data[0] <WRAP>\n" +
" </WRAP>data[1], <WRAP> \n" +
" </WRAP>data[2], \n" +
" data[3], \n" +
" <FOLD>data[4], \n" +
" data[5], \n" +
" data[6], </FOLD> \n" +
" data[7], \n" +
" data[8] <WRAP> \n" +
" </WRAP>data[9], <WRAP> \n" +
" </WRAP>data[10]); \n" +
" }\n" +
" public void bar(int ... i) {\n" +
" }\n" +
@@ -346,7 +376,7 @@ public class SoftWrapDataMapperTest {
@Nullable
private FoldRegion getCollapsedFoldRegion(int offset) {
for (FoldRegion region : myFoldRegions) {
if (region.getStartOffset() == offset) {
if (region.getStartOffset() <= offset && region.getEndOffset() > offset) {
return region;
}
}
@@ -424,15 +454,15 @@ public class SoftWrapDataMapperTest {
}
// Check visual by logical.
VisualPosition actualVisual = myAdjuster.adjustVisualPosition(data.logical, toSoftWrapUnawareVisual(data));
if (!actualVisual.equals(data.visual)) {
myAdjuster.adjustVisualPosition(data.logical, toSoftWrapUnawareVisual(data));
throw new AssertionError(
String.format("Detected unmatched visual position by logical. Expected: '%s', actual: '%s'. Calculation was performed "
+ "against logical position: '%s' and soft wrap-unaware visual: '%s'",
data.visual, actualVisual, data.logical, toSoftWrapUnawareVisual(data))
);
}
//VisualPosition actualVisual = myAdjuster.adjustVisualPosition(data.logical, toSoftWrapUnawareVisual(data));
//if (!actualVisual.equals(data.visual)) {
// myAdjuster.adjustVisualPosition(data.logical, toSoftWrapUnawareVisual(data));
// throw new AssertionError(
// String.format("Detected unmatched visual position by logical. Expected: '%s', actual: '%s'. Calculation was performed "
// + "against logical position: '%s' and soft wrap-unaware visual: '%s'",
// data.visual, actualVisual, data.logical, toSoftWrapUnawareVisual(data))
// );
//}
}
}
@@ -471,7 +501,8 @@ public class SoftWrapDataMapperTest {
continue;
}
context.onNewSymbol(documentText.charAt(i));
char c = documentText.charAt(i);
context.onNewSymbol(c);
}
myLineRanges.add(new TextRange(context.logicalLineStartOffset, context.document.length()));
@@ -549,6 +580,7 @@ public class SoftWrapDataMapperTest {
int softWrapLinesBeforeCurrentLogical;
int softWrapLinesOnCurrentLogical;
int softWrapSymbolsOnCurrentVisualLine;
int softWrapColumnDiff;
int foldingStartOffset;
int foldingStartLogicalColumn;
int foldingStartVisualColumn;
@@ -580,8 +612,9 @@ public class SoftWrapDataMapperTest {
public void onFoldingEnd() {
visualColumn += 3; // For '...' folding
foldingColumnDiff += 3;
x = foldingStartX + 3 * SPACE_SIZE;
foldingColumnDiff = visualColumn - logicalColumn;
insideFolding = false;
myFoldRegions.add(new MockFoldRegion(foldingStartOffset, offset));
}
@@ -595,6 +628,10 @@ public class SoftWrapDataMapperTest {
foldedLines++;
offset++;
x = 0;
softWrapColumnDiff = 0;
softWrapLinesBeforeCurrentLogical += softWrapLinesOnCurrentLogical;
softWrapLinesOnCurrentLogical = 0;
foldingColumnDiff = foldingStartVisualColumn;
}
else if (c == '\t') {
int tabWidthInColumns = myRepresentationHelper.toVisualColumnSymbolsNumber(c, x);
@@ -611,12 +648,13 @@ public class SoftWrapDataMapperTest {
logicalColumn++;
offset++;
foldingColumnDiff -= tabWidthInColumns;
} else {
logicalColumn++;
offset++;
x += myRepresentationHelper.charWidth(c, x, Font.PLAIN);
foldingColumnDiff--;
}
foldingColumnDiff = foldingStartVisualColumn - logicalColumn;
return;
}
@@ -627,20 +665,25 @@ public class SoftWrapDataMapperTest {
// Emulate the situation when the user works with a virtual space after document line end (add such virtual
// positions two symbols behind the end).
visualColumn++;
softWrapColumnDiff++;
x += SPACE_SIZE;
addData(true);
visualColumn++;
softWrapColumnDiff++;
x += SPACE_SIZE;
addData(true);
visualLine++;
x = 0;
softWrapLinesOnCurrentLogical++;
softWrapColumnDiff = -logicalColumn + 1;
visualColumn = 1; // For the column reserved for soft wrap sign.
softWrapSymbolsOnCurrentVisualLine = 0;
}
else {
visualColumn++;
softWrapColumnDiff++;
softWrapSymbolsOnCurrentVisualLine++;
x += myRepresentationHelper.charWidth(c, x, Font.PLAIN);
}
@@ -652,6 +695,8 @@ public class SoftWrapDataMapperTest {
if (c == '\n') {
visualLine++;
visualColumn = 0;
foldingColumnDiff = 0;
softWrapColumnDiff = 0;
x = 0;
softWrapLinesBeforeCurrentLogical += softWrapLinesOnCurrentLogical;
softWrapLinesOnCurrentLogical = 0;
@@ -719,7 +764,6 @@ public class SoftWrapDataMapperTest {
private LogicalPosition buildLogicalPosition() {
//int softWrapColumnDiff
int softWrapColumnDiff = visualColumn - logicalColumn - foldingColumnDiff;
return new LogicalPosition(
logicalLine, logicalColumn, softWrapLinesBeforeCurrentLogical, softWrapLinesOnCurrentLogical, softWrapColumnDiff,
foldedLines, foldingColumnDiff
@@ -1171,3 +1171,5 @@ group.ToolsBasicGroup.description=Tools Basic Group
group.ToolbarNewElement.text=Toolbar New Element Group
action.NewElementToolbarAction.text=Create New File
action.ShowRegistry.text=Registry
action.TogglePowerSave.text=Power Save Mode
action.TogglePowerSave.description=Power save mode disables background code analysis and other background operations
@@ -128,6 +128,9 @@
<applicationService serviceInterface="com.intellij.patterns.compiler.PatternCompilerFactory"
serviceImplementation="com.intellij.patterns.compiler.PatternCompilerFactoryImpl"/>
<applicationService serviceInterface="com.intellij.ide.PowerSaveMode"
serviceImplementation="com.intellij.ide.PowerSaveMode"/>
<projectService serviceInterface="com.intellij.psi.codeStyle.ProjectCodeStyleSettingsManager"
serviceImplementation="com.intellij.psi.codeStyle.ProjectCodeStyleSettingsManager"/>
@@ -568,4 +571,6 @@
<applicationService serviceInterface="com.intellij.ide.todo.TodoConfiguration"
serviceImplementation="com.intellij.ide.todo.TodoConfiguration"/>
<indexPatternProvider implementation="com.intellij.ide.todo.TodoIndexPatternProvider"/>
<hectorComponentProvider implementation="com.intellij.codeInsight.daemon.PowerSaveHectorProvider"/>
</extensions>
@@ -80,6 +80,8 @@
<checkoutCompletedListener implementation="com.intellij.openapi.vcs.checkout.PlatformProjectCheckoutListener"/>
<weigher key="proximity" implementationClass="com.intellij.psi.util.proximity.SameDirectoryWeigher" id="sameDirectory"
order="after openedInEditor"/>
</extensions>
<xi:include href="xdebugger.xml" xpointer="xpointer(/root/*)"/>
@@ -70,6 +70,12 @@
<add-to-group group-id="FileMenu" anchor="after" relative-to-action="ChangeFileEncodingGroup"/>
</action>
<group id="PowerSaveGroup">
<separator/>
<action id="TogglePowerSave" class="com.intellij.ide.actions.TogglePowerSaveAction"/>
<add-to-group group-id="FileMenu" anchor="after" relative-to-action="ToggleReadOnlyAttribute"/>
</group>
<!-- Edit -->
<action id="CopyReference" class="com.intellij.ide.actions.CopyReferenceAction">
<add-to-group group-id="CutCopyPasteGroup" anchor="after" relative-to-action="CopyPaths"/>
@@ -38,15 +38,14 @@ public class MergeQuery<T> implements Query<T>{
@NotNull
public Collection<T> findAll() {
List<T> results = new ArrayList<T>();
results.addAll(myQuery1.findAll());
results.addAll(myQuery2.findAll());
forEach(new CommonProcessors.CollectProcessor<T>(results));
return results;
}
public T findFirst() {
final T r1 = myQuery1.findFirst();
if (r1 != null) return r1;
return myQuery2.findFirst();
final CommonProcessors.FindFirstProcessor<T> processor = new CommonProcessors.FindFirstProcessor<T>();
forEach(processor);
return processor.getFoundValue();
}
public boolean forEach(@NotNull final Processor<T> consumer) {
@@ -221,7 +221,7 @@ public class TreeModelBuilder {
final FilePath fp1 = ChangesUtil.getFilePath(o1);
final FilePath fp2 = ChangesUtil.getFilePath(o2);
final int diff = fp1.getPath().length() - fp2.getPath().length();
final int diff = fp1.getIOFile().getPath().length() - fp2.getIOFile().getPath().length();
return diff == 0 ? 0 : (diff < 0 ? -1 : 1);
}
}
@@ -15,11 +15,12 @@
*/
package com.intellij.debugger.ui;
import com.intellij.execution.ui.ExecutionConsole;
import org.jetbrains.annotations.NonNls;
public interface DebuggerContentInfo {
@NonNls String CONSOLE_CONTENT = "ConsoleContent";
@NonNls String CONSOLE_CONTENT = ExecutionConsole.CONSOLE_CONTENT_ID;
@NonNls String THREADS_CONTENT = "ThreadsContent";
@NonNls String VARIABLES_CONTENT = "VariablesContent";
@NonNls String FRAME_CONTENT = "FrameContent";
@@ -21,6 +21,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspection;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor;
@@ -94,10 +95,10 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
if (expectedType == null || PsiType.VOID.equals(expectedType)) return;
ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() {
public boolean visit(Instruction instruction) {
final PsiElement psiElement = instruction.getElement();
if (psiElement instanceof GrExpression) {
checkAssignability(expectedType, (GrExpression)psiElement, (GrExpression)psiElement);
@Override
public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
if (returnValue != null && !(returnValue.getParent() instanceof GrReturnStatement)) {
checkAssignability(expectedType, returnValue, returnValue);
}
return true;
}
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiType;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
import org.jetbrains.plugins.groovy.codeInspection.GroovySuppressableInspectionTool;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
@@ -35,6 +36,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.MaybeReturnInstruction;
@@ -86,7 +88,8 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool {
final Ref<Boolean> hasExplicitReturn = new Ref<Boolean>(false);
final Ref<Boolean> sometimes = new Ref<Boolean>(false);
ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() {
public boolean visit(Instruction instruction) {
@Override
public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
if (instruction instanceof MaybeReturnInstruction) {
if (((MaybeReturnInstruction)instruction).mayReturnValue()) {
sometimes.set(true);
@@ -99,7 +102,7 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool {
final PsiElement element = instruction.getElement();
if (element instanceof GrReturnStatement) {
sometimes.set(true);
if (((GrReturnStatement)element).getReturnValue() != null) {
if (returnValue != null) {
hasExplicitReturn.set(true);
}
}
@@ -543,7 +543,7 @@ public class ControlFlowUtils {
public interface ExitPointVisitor {
boolean visit(Instruction instruction);
boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue);
}
public static void visitAllExitPoints(@Nullable GrCodeBlock block, ExitPointVisitor visitor) {
@@ -556,12 +556,16 @@ public class ControlFlowUtils {
private static boolean visitAllExitPointsInner(Instruction last, Instruction first, boolean[] visited, ExitPointVisitor visitor) {
if (first == last) return true;
if (last instanceof MaybeReturnInstruction) {
return visitor.visit(last);
return visitor.visitExitPoint(last, (GrExpression)last.getElement());
}
final PsiElement element = last.getElement();
PsiElement element = last.getElement();
if (element != null) {
return visitor.visit(last);
if (element instanceof GrReturnStatement) {
element = ((GrReturnStatement)element).getReturnValue();
}
return visitor.visitExitPoint(last, element instanceof GrExpression ? (GrExpression)element : null);
}
visited[last.num()] = true;
for (Instruction pred : last.allPred()) {
@@ -571,4 +575,5 @@ public class ControlFlowUtils {
}
return true;
}
}
@@ -21,25 +21,49 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.psi.stubs.StubIndex;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.stubs.GroovyCacheUtil;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author ven
*/
public class AnnotatedMembersSearcher implements QueryExecutor<PsiMember, AnnotatedElementsSearch.Parameters> {
public class AnnotatedMembersSearcher implements QueryExecutor<PsiModifierListOwner, AnnotatedElementsSearch.Parameters> {
public boolean execute(final AnnotatedElementsSearch.Parameters p, final Processor<PsiMember> consumer) {
@NotNull
private static List<PsiModifierListOwner> getAnnotatedMemberCandidates(PsiClass clazz, GlobalSearchScope scope) {
final String name = clazz.getName();
if (name == null) return Collections.emptyList();
final Collection<PsiElement> members = StubIndex.getInstance().get(GrAnnotatedMemberIndex.KEY, name, clazz.getProject(), scope);
if (members.isEmpty()) {
return Collections.emptyList();
}
final ArrayList<PsiModifierListOwner> result = new ArrayList<PsiModifierListOwner>();
for (PsiElement element : members) {
if (element instanceof GroovyFile) {
element = ((GroovyFile)element).getPackageDefinition();
}
if (element instanceof PsiModifierListOwner) {
result.add((PsiModifierListOwner)element);
}
}
return result;
}
public boolean execute(final AnnotatedElementsSearch.Parameters p, final Processor<PsiModifierListOwner> consumer) {
final PsiClass annClass = p.getAnnotationClass();
assert annClass.isAnnotationType() : "Annotation type should be passed to annotated members search";
@@ -48,29 +72,27 @@ public class AnnotatedMembersSearcher implements QueryExecutor<PsiMember, Annota
final SearchScope scope = p.getScope();
PsiMember[] candidates;
final List<PsiModifierListOwner> candidates;
if (scope instanceof GlobalSearchScope) {
candidates = GroovyCacheUtil.getAnnotatedMemberCandidates(annClass, ((GlobalSearchScope)scope));
candidates = getAnnotatedMemberCandidates(annClass, ((GlobalSearchScope)scope));
} else {
PsiElement[] elements = ((LocalSearchScope)scope).getScope();
final List<GrMember> collector = new ArrayList<GrMember>();
for (PsiElement element : elements) {
candidates = new ArrayList<PsiModifierListOwner>();
for (PsiElement element : ((LocalSearchScope)scope).getScope()) {
if (element instanceof GroovyPsiElement) {
((GroovyPsiElement)element).accept(new GroovyRecursiveElementVisitor() {
public void visitMethod(GrMethod method) {
collector.add(method);
candidates.add(method);
}
public void visitField(GrField field) {
collector.add(field);
candidates.add(field);
}
});
}
}
candidates = collector.toArray(new PsiMember[collector.size()]);
}
for (PsiMember candidate : candidates) {
for (PsiModifierListOwner candidate : candidates) {
if (!AnnotatedElementsSearcher.isInstanceof(candidate, p.getTypes())) {
continue;
}
@@ -78,10 +100,8 @@ public class AnnotatedMembersSearcher implements QueryExecutor<PsiMember, Annota
PsiModifierList list = candidate.getModifierList();
if (list != null) {
for (PsiAnnotation annotation : list.getAnnotations()) {
if (annotationFQN.equals(annotation.getQualifiedName())) {
PsiClass clazz = candidate.getContainingClass();
if (clazz instanceof GroovyScriptClass) continue;
if (!consumer.process(candidate)) return false;
if (annotationFQN.equals(annotation.getQualifiedName()) && !consumer.process(candidate)) {
return false;
}
}
}
@@ -15,26 +15,30 @@
*/
package org.jetbrains.plugins.groovy.findUsages;
import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
/**
* @author ven
*/
public class ConstructorReferencesSearcher implements QueryExecutor<PsiReference, ReferencesSearch.SearchParameters> {
public boolean execute(ReferencesSearch.SearchParameters queryParameters, final Processor<PsiReference> consumer) {
public class ConstructorReferencesSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {
protected ConstructorReferencesSearcher() {
super(true);
}
@Override
public void processQuery(ReferencesSearch.SearchParameters queryParameters, Processor<PsiReference> consumer) {
final PsiElement element = queryParameters.getElementToSearch();
if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
if (method.isConstructor()) {
return GroovyConstructorUsagesSearchHelper.execute(method, queryParameters.getScope(), consumer);
GroovyConstructorUsagesSearcher.processConstructorUsages(method, queryParameters.getScope(), consumer, queryParameters.getOptimizer(), true);
}
}
return true;
}
}
@@ -1,199 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.findUsages;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadActionProcessor;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightMemberReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.Processor;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
/**
* @author Maxim.Medvedev
* Date: May 2, 2009 3:48:53 PM
*/
public class GroovyConstructorUsagesSearchHelper {
private GroovyConstructorUsagesSearchHelper() {
}
public static boolean execute(final PsiMethod constructor, SearchScope searchScope, final Processor<PsiReference> consumer) {
if (!constructor.isConstructor()) return true;
if (searchScope instanceof GlobalSearchScope) {
searchScope = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)searchScope, GroovyFileType.GROOVY_FILE_TYPE);
}
final PsiClass clazz = ApplicationManager.getApplication().runReadAction(new NullableComputable<PsiClass>() {
public PsiClass compute() {
return constructor.getContainingClass();
}
});
if (clazz == null) return true;
//enum constants
if (!ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
if (!clazz.isEnum()) return true;
if (!(clazz instanceof GroovyPsiElement)) return true;
final PsiField[] fields = clazz.getFields();
for (PsiField field : fields) {
if (field instanceof GrEnumConstant) {
final PsiReference ref = field.getReference();
if (ref.isReferenceTo(constructor)) {
if (!consumer.process(ref)) return false;
}
}
}
return true;
}
})) {
return false;
}
ReferencesSearch.search(clazz, searchScope, true).forEach(new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(PsiReference ref) {
final PsiElement element = ref.getElement();
if (element instanceof GrCodeReferenceElement) {
GrNewExpression newExpression = null;
if (element.getParent() instanceof GrNewExpression) {
newExpression = (GrNewExpression)element.getParent();
}
else if (element.getParent() instanceof GrAnonymousClassDefinition) {
newExpression = (GrNewExpression)element.getParent().getParent();
}
if (newExpression != null) {
final PsiMethod resolvedConstructor = newExpression.resolveConstructor();
final PsiManager manager = constructor.getManager();
if (manager.areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) return false;
}
}
return true;
}
});
//this()
if (clazz instanceof GrTypeDefinition) {
if (!processConstructors(constructor, consumer, clazz, true)) {
return false;
}
}
//super : does not work now, need to invent a way for it to work without repository
if (!DirectClassInheritorsSearch.search(clazz, searchScope).forEach(new Processor<PsiClass>() {
public boolean process(PsiClass inheritor) {
if (inheritor instanceof GrTypeDefinition) {
if (!processConstructors(constructor, consumer, inheritor, false)) return false;
}
return true;
}
})) {
return false;
}
return true;
}
private static boolean processConstructors(final PsiMethod constructor, final Processor<PsiReference> consumer, final PsiClass clazz,
final boolean processThisRefs) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
return processClassConstructors(clazz, constructor, consumer, processThisRefs);
}
});
}
private static boolean processClassConstructors(PsiClass clazz,
PsiMethod searchedConstructor,
Processor<PsiReference> consumer,
boolean processThisRefs) {
final PsiMethod[] constructors = clazz.getConstructors();
if (constructors.length == 0) {
processImplicitConstructorCall(clazz, consumer, searchedConstructor);
}
for (PsiMethod constructor : constructors) {
final GrOpenBlock block = ((GrMethod)constructor).getBlock();
if (block != null) {
final GrStatement[] statements = block.getStatements();
if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) {
final GrConstructorInvocation invocation = (GrConstructorInvocation)statements[0];
if (invocation.isThisCall() == processThisRefs &&
invocation.getManager().areElementsEquivalent(invocation.resolveConstructor(), searchedConstructor) &&
!consumer.process(invocation)) {
return false;
}
}
else {
processImplicitConstructorCall(constructor, consumer, searchedConstructor);
}
}
}
return true;
}
private static void processImplicitConstructorCall(final PsiMember usage,
final Processor<PsiReference> processor,
final PsiMethod constructor) {
if (constructor instanceof GrMethod) {
GrParameter[] grParameters = (GrParameter[])constructor.getParameterList().getParameters();
if (grParameters.length > 0 && !grParameters[0].isOptional()) return;
}
else if (constructor.getParameterList().getParameters().length > 0) return;
PsiManager manager = constructor.getManager();
if (manager.areElementsEquivalent(usage, constructor) || manager.areElementsEquivalent(constructor.getContainingClass(), usage.getContainingClass())) return;
processor.process(new LightMemberReference(manager, usage, PsiSubstitutor.EMPTY) {
public PsiElement getElement() {
return usage;
}
public TextRange getRangeInElement() {
if (usage instanceof PsiClass) {
PsiIdentifier identifier = ((PsiClass)usage).getNameIdentifier();
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
}
else if (usage instanceof PsiMethod) {
PsiIdentifier identifier = ((PsiMethod)usage).getNameIdentifier();
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
}
return super.getRangeInElement();
}
});
}
}
@@ -16,20 +16,399 @@
package org.jetbrains.plugins.groovy.findUsages;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.openapi.application.ReadActionProcessor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightMemberReference;
import com.intellij.psi.search.DelegatingGlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.SearchRequestCollector;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.PairProcessor;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
import com.intellij.util.containers.ConcurrentHashSet;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.gpp.GppTypeConverter;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* @author Maxim.Medvedev
*/
public class GroovyConstructorUsagesSearcher implements QueryExecutor<PsiReference, MethodReferencesSearch.SearchParameters> {
public boolean execute(MethodReferencesSearch.SearchParameters p, final Processor<PsiReference> consumer) {
final PsiMethod method = p.getMethod();
final SearchScope searchScope = p.getScope();
return GroovyConstructorUsagesSearchHelper.execute(method, searchScope, consumer);
public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters> {
public GroovyConstructorUsagesSearcher() {
super(true);
}
@Override
public void processQuery(MethodReferencesSearch.SearchParameters p, Processor<PsiReference> consumer) {
processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer(), true);
}
static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor<PsiReference> consumer, final SearchRequestCollector collector, final boolean searchGppCalls) {
if (!constructor.isConstructor()) return;
SearchScope onlyGroovy = searchScope;
if (onlyGroovy instanceof GlobalSearchScope) {
onlyGroovy = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)onlyGroovy, GroovyFileType.GROOVY_FILE_TYPE);
}
final PsiClass clazz = constructor.getContainingClass();
if (clazz == null) return;
if (clazz.isEnum() && clazz instanceof GroovyPsiElement) {
for (PsiField field : clazz.getFields()) {
if (field instanceof GrEnumConstant) {
final PsiReference ref = field.getReference();
if (ref != null && ref.isReferenceTo(constructor)) {
if (!consumer.process(ref)) return;
}
}
}
}
final Set<PsiMethod> processedMethods = new ConcurrentHashSet<PsiMethod>();
ReferencesSearch.searchOptimized(clazz, searchScope, true, collector, true, new PairProcessor<PsiReference, SearchRequestCollector>() {
@Override
public boolean process(PsiReference ref, SearchRequestCollector collector) {
final PsiElement element = ref.getElement();
if (element instanceof GrCodeReferenceElement) {
if (!processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref, !searchGppCalls)) {
return false;
}
}
if (searchGppCalls) {
final PsiMethod method = getMethodToSearchForCallsWithLiteralArguments(element, clazz);
if (method != null && processedMethods.add(method)) {
processGppMethodCalls(clazz, constructor, consumer, searchScope, collector, method);
}
}
return true;
}
});
//this()
if (clazz instanceof GrTypeDefinition) {
if (!processConstructors(constructor, consumer, clazz, true)) {
return;
}
}
//super()
DirectClassInheritorsSearch.search(clazz, onlyGroovy).forEach(new Processor<PsiClass>() {
public boolean process(PsiClass inheritor) {
if (inheritor instanceof GrTypeDefinition) {
if (!processConstructors(constructor, consumer, inheritor, false)) return false;
}
return true;
}
});
}
@Nullable
static PsiMethod getMethodToSearchForCallsWithLiteralArguments(PsiElement element, PsiClass targetClass) {
final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
if (parameter != null) {
final PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class);
if (method != null && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) {
final PsiType parameterType = parameter.getType();
if (parameterType instanceof PsiClassType) {
if (method.getManager().areElementsEquivalent(targetClass, ((PsiClassType)parameterType).resolve())) {
return method;
}
}
}
}
return null;
}
private static void processGppMethodCalls(final PsiClass targetClass,
final PsiMethod originalTarget,
final Processor<PsiReference> originalProcessor,
SearchScope scope,
SearchRequestCollector originalCollector, @NotNull PsiMethod currentTarget) {
final SearchScope gppScope = getGppScope(targetClass.getProject()).intersectWith(scope);
final ReadActionProcessor<PsiReference> gppCallProcessor = new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(PsiReference psiReference) {
if (psiReference instanceof GrReferenceElement) {
final PsiElement parent = ((GrReferenceElement)psiReference).getParent();
if (parent instanceof GrCall) {
final GrArgumentList argList = ((GrCall)parent).getArgumentList();
if (argList != null) {
boolean checkedTypedContext = false;
for (GrExpression argument : argList.getExpressionArguments()) {
if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) {
if (!checkedTypedContext) {
if (!GppTypeConverter.hasTypedContext(parent)) {
return true;
}
checkedTypedContext = true;
}
for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) {
if (psiType instanceof PsiClassType &&
targetClass.getManager().areElementsEquivalent(targetClass, ((PsiClassType)psiType).resolve()) &&
!checkListInstantiation(originalTarget, originalProcessor, (GrListOrMap)argument, (PsiClassType)psiType)) {
return false;
}
}
}
}
}
}
}
return true;
}
};
if (currentTarget.isConstructor()) {
processConstructorUsages(currentTarget, gppScope, gppCallProcessor, originalCollector, false);
}
else {
MethodReferencesSearch.searchOptimized(currentTarget, gppScope, true, originalCollector, gppCallProcessor);
}
}
static GlobalSearchScope getGppScope(final Project project) {
return CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider<GlobalSearchScope>() {
@Override
public Result<GlobalSearchScope> compute() {
return Result.create(calcGppScope(project), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
}
});
}
static boolean processGroovyConstructorUsages(GrCodeReferenceElement element,
final PsiMethod constructor,
final Processor<PsiReference> consumer,
PsiReference ref, boolean usualCallsOnly) {
PsiElement parent = element.getParent();
if (parent instanceof GrAnonymousClassDefinition) {
parent = parent.getParent();
}
if (parent instanceof GrNewExpression) {
final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor();
if (constructor.getManager().areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) {
return false;
}
}
else if (!usualCallsOnly && parent instanceof GrTypeElement) {
final GrTypeElement typeElement = (GrTypeElement)parent;
final PsiElement grandpa = typeElement.getParent();
if (grandpa instanceof GrVariableDeclaration) {
final GrVariable[] vars = ((GrVariableDeclaration)grandpa).getVariables();
if (vars.length == 1) {
final GrVariable variable = vars[0];
if (!checkListInstantiation(constructor, consumer, variable.getInitializerGroovy(), typeElement)) {
return false;
}
}
}
else if (grandpa instanceof GrMethod) {
final GrMethod method = (GrMethod)grandpa;
if (typeElement == method.getReturnTypeElementGroovy()) {
ControlFlowUtils.visitAllExitPoints(method.getBlock(), new ControlFlowUtils.ExitPointVisitor() {
@Override
public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
if (!checkListInstantiation(constructor, consumer, returnValue, typeElement)) {
return false;
}
return true;
}
});
}
}
else if (grandpa instanceof GrTypeCastExpression) {
final GrTypeCastExpression cast = (GrTypeCastExpression)grandpa;
if (cast.getCastTypeElement() == typeElement &&
!checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) {
return false;
}
}
else if (grandpa instanceof GrSafeCastExpression) {
final GrSafeCastExpression cast = (GrSafeCastExpression)grandpa;
if (cast.getCastTypeElement() == typeElement &&
!checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) {
return false;
}
}
}
return true;
}
static GlobalSearchScope calcGppScope(Project project) {
final GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
final GlobalSearchScope maximal = GlobalSearchScope.getScopeRestrictedByFileTypes(allScope, GroovyFileType.GROOVY_FILE_TYPE);
GlobalSearchScope gppExtensions = new DelegatingGlobalSearchScope(maximal) {
@Override
public boolean contains(VirtualFile file) {
return super.contains(file) && GppTypeConverter.isGppExtension(file.getExtension());
}
};
final PsiClass typed = JavaPsiFacade.getInstance(project).findClass(GppTypeConverter.GROOVY_LANG_TYPED, allScope);
if (typed != null) {
final Set<VirtualFile> files = new HashSet<VirtualFile>();
AnnotatedElementsSearch.searchElements(typed, maximal, PsiModifierListOwner.class).forEach(new Processor<PsiModifierListOwner>() {
@Override
public boolean process(PsiModifierListOwner occurrence) {
ContainerUtil.addIfNotNull(occurrence.getContainingFile().getVirtualFile(), files);
return true;
}
});
GlobalSearchScope withTypedAnno = GlobalSearchScope.filesScope(project, files);
return withTypedAnno.union(gppExtensions);
}
return gppExtensions;
}
static boolean checkListInstantiation(PsiMethod constructor,
Processor<PsiReference> consumer,
GrExpression expression, final GrTypeElement typeElement) {
if (expression instanceof GrListOrMap) {
final GrListOrMap list = (GrListOrMap)expression;
if (!list.isMap()) {
final PsiType expectedType = typeElement.getType();
if (expectedType instanceof PsiClassType) {
return checkListInstantiation(constructor, consumer, list, (PsiClassType)expectedType);
}
}
}
return true;
}
static boolean checkListInstantiation(PsiMethod constructor,
Processor<PsiReference> consumer,
GrListOrMap list,
PsiClassType expectedType) {
final PsiType listType = list.getType();
if (listType instanceof GrTupleType) {
for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, ((GrTupleType)listType).getComponentTypes(), list)) {
if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) {
if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) {
return false;
}
}
}
}
return true;
}
static boolean processConstructors(final PsiMethod constructor, final Processor<PsiReference> consumer, final PsiClass clazz,
final boolean processThisRefs) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
return processClassConstructors(clazz, constructor, consumer, processThisRefs);
}
});
}
static boolean processClassConstructors(PsiClass clazz,
PsiMethod searchedConstructor,
Processor<PsiReference> consumer,
boolean processThisRefs) {
final PsiMethod[] constructors = clazz.getConstructors();
if (constructors.length == 0) {
processImplicitConstructorCall(clazz, consumer, searchedConstructor);
}
for (PsiMethod constructor : constructors) {
final GrOpenBlock block = ((GrMethod)constructor).getBlock();
if (block != null) {
final GrStatement[] statements = block.getStatements();
if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) {
final GrConstructorInvocation invocation = (GrConstructorInvocation)statements[0];
if (invocation.isThisCall() == processThisRefs &&
invocation.getManager().areElementsEquivalent(invocation.resolveConstructor(), searchedConstructor) &&
!consumer.process(invocation)) {
return false;
}
}
else {
processImplicitConstructorCall(constructor, consumer, searchedConstructor);
}
}
}
return true;
}
static void processImplicitConstructorCall(final PsiMember usage,
final Processor<PsiReference> processor,
final PsiMethod constructor) {
if (constructor instanceof GrMethod) {
GrParameter[] grParameters = (GrParameter[])constructor.getParameterList().getParameters();
if (grParameters.length > 0 && !grParameters[0].isOptional()) return;
}
else if (constructor.getParameterList().getParameters().length > 0) return;
PsiManager manager = constructor.getManager();
if (manager.areElementsEquivalent(usage, constructor) || manager.areElementsEquivalent(constructor.getContainingClass(), usage.getContainingClass())) return;
processor.process(new LightMemberReference(manager, usage, PsiSubstitutor.EMPTY) {
public PsiElement getElement() {
return usage;
}
public TextRange getRangeInElement() {
if (usage instanceof PsiClass) {
PsiIdentifier identifier = ((PsiClass)usage).getNameIdentifier();
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
}
else if (usage instanceof PsiMethod) {
PsiIdentifier identifier = ((PsiMethod)usage).getNameIdentifier();
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
}
return super.getRangeInElement();
}
});
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.*;
@@ -49,7 +50,7 @@ public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnh
if (listType instanceof GrTupleType) {
for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(list)) {
if (type instanceof PsiClassType) {
for (GroovyResolveResult resolveResult : GppTypeConverter
for (GroovyResolveResult resolveResult : PsiUtil
.getConstructorCandidates((PsiClassType)type, ((GrTupleType)listType).getComponentTypes(), closure)) {
final PsiElement method = resolveResult.getElement();
if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) {
@@ -10,6 +10,7 @@ import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesPr
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SubtypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.ArrayList;
import java.util.Arrays;
@@ -48,7 +49,7 @@ public class GppExpectedTypesContributor extends GroovyExpectedTypesContributor
final ArrayList<TypeConstraint> result = new ArrayList<TypeConstraint>();
for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(expression)) {
if (type instanceof PsiClassType) {
for (GroovyResolveResult resolveResult : GppTypeConverter.getConstructorCandidates((PsiClassType)type, argTypes, expression)) {
for (GroovyResolveResult resolveResult : PsiUtil.getConstructorCandidates((PsiClassType)type, argTypes, expression)) {
final PsiElement method = resolveResult.getElement();
if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) {
final PsiParameter[] constructorParameters = ((PsiMethod)method).getParameterList().getParameters();
@@ -7,12 +7,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.dsl.toplevel.AnnotatedContextFilter;
import org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
@@ -21,26 +19,29 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
*/
public class GppTypeConverter extends GrTypeConverter {
public static final String GROOVY_LANG_TYPED = "groovy.lang.Typed";
public static boolean hasTypedContext(PsiElement context) {
if (context == null) {
return false;
}
if (AnnotatedContextFilter.hasAnnotatedContext(context, "groovy.lang.Typed")) {
if (AnnotatedContextFilter.hasAnnotatedContext(context, GROOVY_LANG_TYPED)) {
return true;
}
final VirtualFile vfile = context.getContainingFile().getOriginalFile().getVirtualFile();
if (vfile != null) {
final String extension = vfile.getExtension();
if ("gpp".equals(extension) || "grunit".equals(vfile.getExtension())) {
return true;
}
if (vfile != null && isGppExtension(vfile.getExtension())) {
return true;
}
return false;
}
public static boolean isGppExtension(String extension) {
return "gpp".equals(extension) || "grunit".equals(extension);
}
@Override
public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) {
if (rType instanceof GrTupleType) {
@@ -93,21 +94,7 @@ public class GppTypeConverter extends GrTypeConverter {
}
private static boolean hasConstructor(PsiClassType lType, PsiType[] argTypes, GroovyPsiElement context) {
return getConstructorCandidates(lType, argTypes, context).length == 1;
}
public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) {
final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (psiClass == null) {
return GroovyResolveResult.EMPTY_ARRAY;
}
final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult
? (GroovyResolveResult)resolveResult
: new GroovyResolveResultImpl(psiClass, context, substitutor, true, true);
return org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes);
return org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates(lType, argTypes, context).length == 1;
}
}
@@ -16,10 +16,7 @@
package org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.UserDataHolderEx;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifierListOwner;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement;
@@ -28,10 +25,11 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
/**
* @author ilyas
*/
public interface GrPackageDefinition
extends UserDataHolderEx, Cloneable, Iconable, PsiElement, NavigationItem, GrTopStatement {
public interface GrPackageDefinition extends GrTopStatement, PsiModifierListOwner {
@Nullable
String getPackageName();
@Nullable
GrCodeReferenceElement getPackageReference();
@Nullable
@@ -107,16 +107,19 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
if (!(block.getParent() instanceof GrBlockStatement && block.getParent().getParent() instanceof GrLoopStatement)) {
final GrStatement[] statements = block.getStatements();
if (statements.length > 0) {
final GrStatement last = statements[statements.length - 1];
if (last instanceof GrExpression) {
final MaybeReturnInstruction instruction = new MaybeReturnInstruction((GrExpression)last, myInstructionNumber++);
checkPending(instruction);
addNode(instruction);
}
handlePossibleReturn(statements[statements.length - 1]);
}
}
}
private void handlePossibleReturn(GrStatement last) {
if (last instanceof GrExpression) {
final MaybeReturnInstruction instruction = new MaybeReturnInstruction((GrExpression)last, myInstructionNumber++);
checkPending(instruction);
addNode(instruction);
}
}
public Instruction[] buildControlFlow(GroovyPsiElement scope, GroovyPsiElement startInScope, GroovyPsiElement endInScope) {
myInstructions = new ArrayList<InstructionImpl>();
myProcessingStack = new Stack<InstructionImpl>();
@@ -386,6 +389,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
condition.accept(this);
}
thenBranch.accept(this);
handlePossibleReturn(thenBranch);
addPendingEdge(ifStatement, myHead);
}
@@ -402,6 +406,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
final GrStatement elseBranch = ifStatement.getElseBranch();
if (elseBranch != null) {
elseBranch.accept(this);
handlePossibleReturn(elseBranch);
addPendingEdge(ifStatement, myHead);
}
@@ -18,12 +18,23 @@ package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.stubs.StubIndex;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
import org.jetbrains.plugins.groovy.lang.stubs.GroovyCacheUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnonymousClassIndex;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrDirectInheritorsIndex;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author ven
@@ -32,6 +43,26 @@ class GroovyDirectInheritorsSearcher implements QueryExecutor<PsiClass, DirectCl
public GroovyDirectInheritorsSearcher() {
}
@NotNull
private static PsiClass[] getDeriverCandidates(PsiClass clazz, GlobalSearchScope scope) {
final String name = clazz.getName();
if (name == null) return GrTypeDefinition.EMPTY_ARRAY;
final ArrayList<PsiClass> inheritors = new ArrayList<PsiClass>();
final Collection<GrReferenceList> refLists = StubIndex.getInstance().get(GrDirectInheritorsIndex.KEY, name, clazz.getProject(), scope);
for (GrReferenceList list : refLists) {
final PsiElement parent = list.getParent();
if (parent instanceof GrTypeDefinition) {
inheritors.add(GrClassSubstitutor.getSubstitutedClass(((GrTypeDefinition)parent)));
}
}
final Collection<GrAnonymousClassDefinition> classes =
StubIndex.getInstance().get(GrAnonymousClassIndex.KEY, name, clazz.getProject(), scope);
for (GrAnonymousClassDefinition aClass : classes) {
inheritors.add(aClass);
}
return inheritors.toArray(new PsiClass[inheritors.size()]);
}
public boolean execute(DirectClassInheritorsSearch.SearchParameters queryParameters, final Processor<PsiClass> consumer) {
final PsiClass clazz = queryParameters.getClassToProcess();
final SearchScope scope = queryParameters.getScope();
@@ -39,7 +70,7 @@ class GroovyDirectInheritorsSearcher implements QueryExecutor<PsiClass, DirectCl
final PsiClass[] candidates = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass[]>() {
public PsiClass[] compute() {
if (!clazz.isValid()) return PsiClass.EMPTY_ARRAY;
return GroovyCacheUtil.getDeriverCandidates(clazz, (GlobalSearchScope)scope);
return getDeriverCandidates(clazz, (GlobalSearchScope)scope);
}
});
for (final PsiClass candidate : candidates) {
@@ -17,6 +17,9 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.toplevel.packaging;
import com.intellij.lang.ASTNode;
import com.intellij.psi.Modifier;
import com.intellij.psi.PsiModifierList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
@@ -56,4 +59,15 @@ public class GrPackageDefinitionImpl extends GroovyPsiElementImpl implements GrP
public GrModifierList getAnnotationList() {
return (GrModifierList)findChildByType(GroovyElementTypes.MODIFIERS);
}
@Override
public PsiModifierList getModifierList() {
return getAnnotationList();
}
@Override
public boolean hasModifierProperty(@Modifier @NonNls @NotNull String name) {
final PsiModifierList list = getModifierList();
return list != null && list.hasExplicitModifier(name);
}
}
@@ -15,17 +15,63 @@
*/
package org.jetbrains.plugins.groovy.lang.psi.stubs;
import com.intellij.psi.stubs.PsiFileStub;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.stubs.PsiFileStubImpl;
import com.intellij.psi.tree.IStubFileElementType;
import com.intellij.util.ArrayUtil;
import com.intellij.util.io.StringRef;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParserDefinition;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
import org.jetbrains.plugins.groovy.lang.psi.stubs.elements.GrTypeDefinitionElementType;
/**
* @author ilyas
*/
public interface GrFileStub extends PsiFileStub<GroovyFile> {
StringRef getPackageName();
public class GrFileStub extends PsiFileStubImpl<GroovyFile> {
private final String[] myAnnotations;
private final StringRef myPackageName;
private final StringRef myName;
private final boolean isScript;
StringRef getName();
public GrFileStub(GroovyFile file) {
super(file);
myPackageName = StringRef.fromString(file.getPackageName());
myName = StringRef.fromString(StringUtil.trimEnd(file.getName(), ".groovy"));
isScript = file.isScript();
final GrPackageDefinition definition = file.getPackageDefinition();
if (definition != null) {
myAnnotations = GrTypeDefinitionElementType.getAnnotationNames(definition);
} else {
myAnnotations = ArrayUtil.EMPTY_STRING_ARRAY;
}
}
boolean isScript();
public GrFileStub(StringRef packName, StringRef name, boolean isScript, String[] annotations) {
super(null);
myPackageName = packName;
myName = name;
this.isScript = isScript;
myAnnotations = annotations;
}
public IStubFileElementType getType() {
return GroovyParserDefinition.GROOVY_FILE;
}
public StringRef getPackageName() {
return myPackageName;
}
public StringRef getName() {
return myName;
}
public boolean isScript() {
return isScript;
}
public String[] getAnnotations() {
return myAnnotations;
}
}
@@ -58,5 +58,21 @@ public class GrStubUtils {
dataStream.writeUTF(namepParameter);
}
}
}
}
public static void writeStringArray(StubOutputStream dataStream, String[] array) throws IOException {
dataStream.writeByte(array.length);
for (String s : array) {
dataStream.writeName(s);
}
}
public static String[] readStringArray(StubInputStream dataStream) throws IOException {
final byte b = dataStream.readByte();
final String[] annNames = new String[b];
for (int i = 0; i < b; i++) {
annNames[i] = dataStream.readName().toString();
}
return annNames;
}
}
@@ -19,7 +19,6 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.stubs.DefaultStubBuilder;
import com.intellij.psi.stubs.StubElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFileStubImpl;
/**
* @author ilyas
@@ -27,7 +26,7 @@ import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFileStubImpl;
public class GroovyFileStubBuilder extends DefaultStubBuilder {
protected StubElement createStubForFile(final PsiFile file) {
if (file instanceof GroovyFile && ((GroovyFile) file).isScript()) {
return new GrFileStubImpl((GroovyFile)file);
return new GrFileStub((GroovyFile)file);
}
return super.createStubForFile(file);
@@ -21,16 +21,10 @@ import com.intellij.psi.stubs.IndexSink;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
import com.intellij.psi.stubs.StubOutputStream;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.StringRef;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GrStubElementType;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.GrFieldImpl;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFieldStub;
import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFieldStubImpl;
@@ -64,22 +58,7 @@ public class GrFieldElementType extends GrStubElementType<GrFieldStub, GrField>
}
public GrFieldStub createStub(GrField psi, StubElement parentStub) {
final GrModifierList modifiers = psi.getModifierList();
String[] annNames;
if (modifiers == null) {
annNames = ArrayUtil.EMPTY_STRING_ARRAY;
}
else {
final GrAnnotation[] annotations = modifiers.getAnnotations();
annNames = ContainerUtil.map(annotations, new Function<GrAnnotation, String>() {
@Nullable
public String fun(final GrAnnotation grAnnotation) {
final GrCodeReferenceElement element = grAnnotation.getClassReference();
if (element == null) return null;
return element.getReferenceName();
}
}, new String[annotations.length]);
}
String[] annNames = GrTypeDefinitionElementType.getAnnotationNames(psi);
Set<String>[] namedParametersArray = new Set[0];
if (psi instanceof GrFieldImpl){
@@ -20,15 +20,9 @@ import com.intellij.psi.stubs.IndexSink;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
import com.intellij.psi.stubs.StubOutputStream;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.StringRef;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GrStubElementType;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.members.GrMethodImpl;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrMethodStub;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrStubUtils;
@@ -37,7 +31,9 @@ import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrMethodNameIndex;
import java.io.IOException;
import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author ilyas
@@ -57,42 +53,22 @@ public class GrMethodElementType extends GrStubElementType<GrMethodStub, GrMetho
}
public GrMethodStub createStub(GrMethod psi, StubElement parentStub) {
final GrModifierList modifiers = psi.getModifierList();
final GrAnnotation[] annotations = modifiers.getAnnotations();
String[] annNames = ContainerUtil.map(annotations, new Function<GrAnnotation, String>() {
@Nullable
public String fun(final GrAnnotation grAnnotation) {
final GrCodeReferenceElement element = grAnnotation.getClassReference();
if (element == null) return null;
return element.getReferenceName();
}
}, new String[annotations.length]);
Set<String>[] namedParametersArray;
namedParametersArray = psi.getNamedParametersArray();
return new GrMethodStubImpl(parentStub, StringRef.fromString(psi.getName()), annNames, namedParametersArray);
return new GrMethodStubImpl(parentStub, StringRef.fromString(psi.getName()), GrTypeDefinitionElementType.getAnnotationNames(psi),
psi.getNamedParametersArray());
}
public void serialize(GrMethodStub stub, StubOutputStream dataStream) throws IOException {
dataStream.writeName(stub.getName());
final String[] annotations = stub.getAnnotations();
dataStream.writeByte(annotations.length);
for (String s : annotations) {
dataStream.writeName(s);
}
GrStubUtils.writeStringArray(dataStream, stub.getAnnotations());
final Set<String>[] namedParameters = stub.getNamedParameters();
GrStubUtils.serializeCollectionsArray(dataStream, namedParameters);
}
public GrMethodStub deserialize(StubInputStream dataStream, StubElement parentStub) throws IOException {
StringRef ref = dataStream.readName();
final byte b = dataStream.readByte();
final String[] annNames = new String[b];
for (int i = 0; i < b; i++) {
annNames[i] = dataStream.readName().toString();
}
final String[] annNames = GrStubUtils.readStringArray(dataStream);
final List<Set<String>> namedParametersSets = GrStubUtils.deserializeCollectionsArray(dataStream);
return new GrMethodStubImpl(parentStub, ref, annNames, namedParametersSets.toArray(new HashSet[0]));
@@ -21,8 +21,9 @@ import com.intellij.psi.stubs.*;
import com.intellij.psi.tree.IStubFileElementType;
import com.intellij.util.io.StringRef;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFileStub;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrStubUtils;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GroovyFileStubBuilder;
import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFileStubImpl;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrFullScriptNameIndex;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrScriptClassNameIndex;
@@ -43,7 +44,7 @@ public class GrStubFileElementType extends IStubFileElementType<GrFileStub> {
@Override
public int getStubVersion() {
return super.getStubVersion() + 5;
return super.getStubVersion() + 6;
}
public String getExternalId() {
@@ -60,6 +61,7 @@ public class GrStubFileElementType extends IStubFileElementType<GrFileStub> {
dataStream.writeName(stub.getPackageName().toString());
dataStream.writeName(stub.getName().toString());
dataStream.writeBoolean(stub.isScript());
GrStubUtils.writeStringArray(dataStream, stub.getAnnotations());
}
@Override
@@ -67,7 +69,7 @@ public class GrStubFileElementType extends IStubFileElementType<GrFileStub> {
StringRef packName = dataStream.readName();
StringRef name = dataStream.readName();
boolean isScript = dataStream.readBoolean();
return new GrFileStubImpl(packName, name, isScript);
return new GrFileStub(packName, name, isScript, GrStubUtils.readStringArray(dataStream));
}
public void indexStub(GrFileStub stub, IndexSink sink) {
@@ -78,6 +80,10 @@ public class GrStubFileElementType extends IStubFileElementType<GrFileStub> {
final String fqn = pName == null || pName.length() == 0 ? name : pName + "." + name;
sink.occurrence(GrFullScriptNameIndex.KEY, fqn.hashCode());
}
for (String anno : stub.getAnnotations()) {
sink.occurrence(GrAnnotatedMemberIndex.KEY, anno);
}
}
}
@@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.stubs.elements;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiNameHelper;
import com.intellij.psi.impl.java.stubs.index.JavaFullClassNameIndex;
import com.intellij.psi.impl.java.stubs.index.JavaShortClassNameIndex;
@@ -59,7 +60,7 @@ public abstract class GrTypeDefinitionElementType<TypeDef extends GrTypeDefiniti
flags);
}
private static String[] getAnnotationNames(GrTypeDefinition psi) {
public static String[] getAnnotationNames(PsiModifierListOwner psi) {
List<String> annoNames = CollectionFactory.arrayList();
final PsiModifierList modifierList = psi.getModifierList();
if (modifierList instanceof GrModifierList) {
@@ -1,63 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang.psi.stubs.impl;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.stubs.PsiFileStubImpl;
import com.intellij.psi.tree.IStubFileElementType;
import com.intellij.util.io.StringRef;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParserDefinition;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFileStub;
/**
* @author ilyas
*/
public class GrFileStubImpl extends PsiFileStubImpl<GroovyFile> implements GrFileStub {
private final StringRef myPackageName;
private final StringRef myName;
private final boolean isScript;
public GrFileStubImpl(GroovyFile file) {
super(file);
myPackageName = StringRef.fromString(file.getPackageName());
myName = StringRef.fromString(StringUtil.trimEnd(file.getName(), ".groovy"));
isScript = file.isScript();
}
public GrFileStubImpl(StringRef packName, StringRef name, boolean isScript) {
super(null);
myPackageName = packName;
myName = name;
this.isScript = isScript;
}
public IStubFileElementType getType() {
return GroovyParserDefinition.GROOVY_FILE;
}
public StringRef getPackageName() {
return myPackageName;
}
public StringRef getName() {
return myName;
}
public boolean isScript() {
return isScript;
}
}
@@ -15,17 +15,17 @@
*/
package org.jetbrains.plugins.groovy.lang.psi.stubs.index;
import com.intellij.psi.PsiMember;
import com.intellij.psi.PsiElement;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
/**
* @author ilyas
*/
public class GrAnnotatedMemberIndex extends StringStubIndexExtension<PsiMember> {
public static final StubIndexKey<String, PsiMember> KEY = StubIndexKey.createIndexKey("gr.annot.members");
public class GrAnnotatedMemberIndex extends StringStubIndexExtension<PsiElement> {
public static final StubIndexKey<String, PsiElement> KEY = StubIndexKey.createIndexKey("gr.annot.members");
public StubIndexKey<String, PsiMember> getKey() {
public StubIndexKey<String, PsiElement> getKey() {
return KEY;
}
}
@@ -66,6 +66,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.JavaIdentifier;
@@ -939,4 +940,18 @@ public class PsiUtil {
}
return (GrReferenceExpression)replaced;
}
public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) {
final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (psiClass == null) {
return GroovyResolveResult.EMPTY_ARRAY;
}
final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult
? (GroovyResolveResult)resolveResult
: new GroovyResolveResultImpl(psiClass, context, substitutor, true, true);
return getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes);
}
}
@@ -1,70 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang.stubs;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMember;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubIndex;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnonymousClassIndex;
import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrDirectInheritorsIndex;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author ilyas
*/
public abstract class GroovyCacheUtil {
@NotNull
public static PsiMember[] getAnnotatedMemberCandidates(PsiClass clazz, GlobalSearchScope scope) {
final String name = clazz.getName();
if (name == null) return GrMember.EMPTY_ARRAY;
final Collection<PsiMember> members = StubIndex.getInstance().get(GrAnnotatedMemberIndex.KEY, name, clazz.getProject(), scope);
return members.toArray(new PsiMember[members.size()]);
}
@NotNull
public static PsiClass[] getDeriverCandidates(PsiClass clazz, GlobalSearchScope scope) {
final String name = clazz.getName();
if (name == null) return GrTypeDefinition.EMPTY_ARRAY;
final ArrayList<PsiClass> inheritors = new ArrayList<PsiClass>();
final Collection<GrReferenceList> refLists = StubIndex.getInstance().get(GrDirectInheritorsIndex.KEY, name, clazz.getProject(), scope);
for (GrReferenceList list : refLists) {
final PsiElement parent = list.getParent();
if (parent instanceof GrTypeDefinition) {
inheritors.add(GrClassSubstitutor.getSubstitutedClass(((GrTypeDefinition)parent)));
}
}
final Collection<GrAnonymousClassDefinition> classes =
StubIndex.getInstance().get(GrAnonymousClassIndex.KEY, name, clazz.getProject(), scope);
for (GrAnonymousClassDefinition aClass : classes) {
inheritors.add(aClass);
}
return inheritors.toArray(new PsiClass[inheritors.size()]);
}
}
@@ -0,0 +1,103 @@
package org.jetbrains.plugins.groovy.lang
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import com.intellij.psi.search.searches.ReferencesSearch
/**
* @author peter
*/
class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase {
@Override protected void setUp() {
super.setUp();
myFixture.addClass("package groovy.lang; public @interface Typed {}");
}
public void testList_Variable() throws Exception {
def foo = myFixture.addClass("""class Foo {
Foo() {}
}
""")
myFixture.addFileToProject "a.groovy", "Foo x = []"
assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll())
}
public void testList_ReturnValue() throws Exception {
def foo = myFixture.addClass("""class Foo {
Foo() {}
}
""")
myFixture.addFileToProject "a.groovy", "Foo foo() { if (true) [] else return [] }"
assertEquals(2, ReferencesSearch.search(foo.constructors[0]).findAll().size())
}
public void testList_Cast() throws Exception {
def foo = myFixture.addClass("""class Foo {
Foo() {}
}
""")
myFixture.addFileToProject "a.groovy", "def x = (Foo) []"
assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll())
}
public void testList_AsCast() throws Exception {
def foo = myFixture.addClass("""class Foo {
Foo() {}
}
}""")
myFixture.addFileToProject "a.groovy", "def x = [] as Foo"
assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll())
}
public void testList_GppMethodCall() throws Exception {
//------------------------declarations
def foo = myFixture.addClass("""
package z;
class Foo {
public Foo() {}
}
""")
myFixture.addClass("""
package z;
public class Bar {
public static void giveMeFoo(int a, Foo f) {}
}
""")
myFixture.addFileToProject("Decl.groovy", "static def giveMeFooAsWell(z.Foo f) {}")
//----------------------usages
myFixture.addFileToProject "a.gpp", "z.Bar.giveMeFoo(2, []) //usage"
myFixture.addFileToProject "b.groovy", """
@Typed package aa;
z.Bar.giveMeFoo(3, []) //usage
"""
myFixture.addFileToProject "c.groovy", """
@Typed def someMethod() {
z.Bar.giveMeFoo 4, [] //usage
Decl.giveMeFooAsWell([]) //usage
}
z.Bar.giveMeFoo 5, [] //non-typed context
Decl.giveMeFooAsWell([])
"""
myFixture.addFileToProject "invalid.gpp", "z.Bar.giveMeFoo 42, 239, []"
myFixture.addFileToProject "nonGpp.groovy", "z.Bar.giveMeFoo(6, [])"
assertEquals(4, ReferencesSearch.search(foo.constructors[0]).findAll().size())
}
public void testList_GppConstructorCallWithSeveralParameters() throws Exception {
def foo = myFixture.addClass("""
class Foo {
Foo() {}
}
""")
myFixture.addClass("""
class Bar {
Bar(Foo f1, Foo f2, Foo f3) {}
}
""")
myFixture.addFileToProject "a.gpp", "new Bar([],[],[])"
assertEquals(3, ReferencesSearch.search(foo.constructors[0]).findAll().size())
}
}
+3 -2
View File
@@ -7,6 +7,7 @@ if (true) {
0(1) element: null
1(2,4) element: IF statement
2(3) WRITE a
3(5) element: Assignment expression MAYBE_RETURN
3(6) element: Assignment expression MAYBE_RETURN
4(5) WRITE a
5() element: null
5(6) element: Assignment expression MAYBE_RETURN
6() element: null
@@ -3,17 +3,20 @@ else if (!(o instanceof Integer)) b = 2
else b = 3
-----
0(1) element: null
1(2,5) element: IF statement
1(2,6) element: IF statement
2(3) READ o
3(4) assertion: o instanceof String
4(14) WRITE b
5(6) READ o
6(7) assertion: ! o instanceof String
7(8,11) element: IF statement
8(9) READ o
9(10) assertion: ! o instanceof Integer
10(14) WRITE b
11(12) READ o
12(13) assertion: o instanceof Integer
13(14) WRITE b
14() element: null
4(5) WRITE b
5(17) element: Assignment expression MAYBE_RETURN
6(7) READ o
7(8) assertion: ! o instanceof String
8(9,13) element: IF statement
9(10) READ o
10(11) assertion: ! o instanceof Integer
11(12) WRITE b
12(17) element: Assignment expression MAYBE_RETURN
13(14) READ o
14(15) assertion: o instanceof Integer
15(16) WRITE b
16(17) element: Assignment expression MAYBE_RETURN
17() element: null
@@ -616,11 +616,17 @@ public class SvnUtil {
}
public static boolean doesRepositorySupportMergeinfo(final SvnVcs vcs, final SVNURL url) {
SVNRepository repository = null;
try {
return vcs.createRepository(url).hasCapability(SVNCapability.MERGE_INFO);
repository = vcs.createRepository(url);
return repository.hasCapability(SVNCapability.MERGE_INFO);
}
catch (SVNException e) {
return false;
} finally {
if (repository != null) {
repository.closeSession();
}
}
}
}
@@ -133,6 +133,8 @@ public class CompareWithBranchAction extends AnAction implements DumbAware {
SVNWCAccess wcAccess = vcs.createWCAccess();
SVNRepository repository = null;
SVNRepository repository2 = null;
try {
SVNAdminAreaInfo info = wcAccess.openAnchor(new File(myVirtualFile.getPath()), false, SVNWCAccess.INFINITE_DEPTH);
File anchorPath = info.getAnchor().getRoot();
@@ -150,18 +152,25 @@ public class CompareWithBranchAction extends AnAction implements DumbAware {
}
SVNURL anchorURL = anchorEntry.getSVNURL();
SVNRepository repository = vcs.createRepository(anchorURL.toString());
repository = vcs.createRepository(anchorURL.toString());
SVNReporter reporter = new SVNReporter(info, info.getAnchor().getFile(info.getTargetName()), false, true, SVNDepth.INFINITY,
false, false, true, SVNDebugLog.getDefaultLog());
long rev = repository.getLatestRevision();
repository2 = vcs.createRepository((target == null) ? url.toString() : url.removePathTail().toString());
SvnDiffEditor diffEditor = new SvnDiffEditor((target == null) ? myVirtualFile : myVirtualFile.getParent(),
vcs.createRepository((target == null) ? url.toString() : url.removePathTail().toString()), rev, true);
repository2, rev, true);
repository.diff(url, rev, rev, target, true, true, false, reporter,
SVNCancellableEditor.newInstance(diffEditor, new SvnProgressCanceller(), null));
changes.addAll(diffEditor.getChangesMap().values());
}
finally {
wcAccess.close();
if (repository != null) {
repository.closeSession();
}
if (repository2 != null) {
repository2.closeSession();
}
}
}
catch(SVNCancelException ex) {
@@ -27,6 +27,7 @@ import org.jetbrains.idea.svn.SvnConfiguration;
import org.jetbrains.idea.svn.SvnServerFileManager;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.io.SVNRepository;
import javax.swing.*;
import java.awt.*;
@@ -137,10 +138,16 @@ public class SvnConfigureProxiesDialog extends DialogWrapper implements Validati
if (pi != null) {
pi.setText("Connecting to " + url);
}
SVNRepository repository = null;
try {
SvnVcs.getInstance(myProject).createRepository(url).testConnection();
repository = SvnVcs.getInstance(myProject).createRepository(url);
repository.testConnection();
} catch (SVNException exc) {
excRef.set(exc);
} finally {
if (repository != null) {
repository.closeSession();
}
}
}
}, "Test connection", true, myProject);
@@ -23,6 +23,7 @@ import org.jetbrains.idea.svn.update.UpdateEventHandler;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNDiffClient;
import org.tmatesoft.svn.core.wc.SVNDiffOptions;
import org.tmatesoft.svn.core.wc.SVNRevision;
@@ -55,11 +56,17 @@ public class BranchMerger implements IMerger {
myBranchName = branchName;
mySourceCopyRevision = sourceCopyRevision;
myAtStart = true;
SVNRepository repository = null;
try {
mySourceLatestRevision = myVcs.createRepository(mySourceUrl).getLatestRevision();
repository = myVcs.createRepository(mySourceUrl);
mySourceLatestRevision = repository.getLatestRevision();
}
catch (SVNException e) {
mySourceLatestRevision = SVNRevision.HEAD.getNumber();
} finally {
if (repository != null) {
repository.closeSession();
}
}
}
@@ -1099,10 +1099,13 @@ public class RepositoryBrowserDialog extends DialogWrapper {
SVNRepository sourceRepository = myVCS.createRepository(sourceURL.toString());
sourceRepository.setCanceller(new SvnProgressCanceller());
SvnDiffEditor diffEditor;
final long rev = sourceRepository.getLatestRevision();
final long rev;
SVNRepository targetRepository = null;
try {
rev = sourceRepository.getLatestRevision();
// generate Map of path->Change
diffEditor = new SvnDiffEditor(sourceRepository, myVCS.createRepository(targetURL.toString()), -1, false);
targetRepository = myVCS.createRepository(targetURL.toString());
diffEditor = new SvnDiffEditor(sourceRepository, targetRepository, -1, false);
final ISVNEditor cancellableEditor = SVNCancellableEditor.newInstance(diffEditor, new SvnProgressCanceller(), null);
sourceRepository.diff(targetURL, rev, rev, null, true, true, false, new ISVNReporterBaton() {
public void report(ISVNReporter reporter) throws SVNException {
@@ -1113,6 +1116,9 @@ public class RepositoryBrowserDialog extends DialogWrapper {
}
finally {
sourceRepository.closeSession();
if (targetRepository != null) {
targetRepository.closeSession();
}
}
final String sourceTitle = SVNPathUtil.tail(sourceURL.toString());
final String targetTitle = SVNPathUtil.tail(targetURL.toString());
@@ -120,12 +120,16 @@ public class SelectLocationDialog extends DialogWrapper {
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
SVNRepository repos = null;
try {
SVNRepository repos = SvnVcs.getInstance(project).createRepository(urlString);
repos = SvnVcs.getInstance(project).createRepository(urlString);
result.set(repos.getRepositoryRoot(true));
repos.closeSession();
} catch (SVNException e) {
excRef.set(e);
} finally {
if (repos != null) {
repos.closeSession();
}
}
}
}, "Detecting repository root", true, project);
@@ -184,13 +184,17 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
}
final String repositoryRoot;
SVNRepository repository = null;
try {
final SVNRepository repository = myVcs.createRepository(svnLocation.getURL());
repository = myVcs.createRepository(svnLocation.getURL());
repositoryRoot = repository.getRepositoryRoot(true).toString();
repository.closeSession();
}
catch (SVNException e) {
throw new VcsException(e);
} finally {
if (repository != null) {
repository.closeSession();
}
}
final ChangeBrowserSettings.Filter filter = settings.createFilter();
@@ -219,13 +223,18 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
}
final String repositoryRoot;
SVNRepository repository = null;
try {
final SVNRepository repository = myVcs.createRepository(svnLocation.getURL());
repository = myVcs.createRepository(svnLocation.getURL());
repositoryRoot = repository.getRepositoryRoot(true).toString();
repository.closeSession();
}
catch (SVNException e) {
throw new VcsException(e);
} finally {
if (repository != null) {
repository.closeSession();
}
}
getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer<SVNLogEntry>() {
@@ -249,13 +258,17 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
}
final String repositoryRoot;
SVNRepository repository = null;
try {
final SVNRepository repository = myVcs.createRepository(svnLocation.getURL());
repository = myVcs.createRepository(svnLocation.getURL());
repositoryRoot = repository.getRepositoryRoot(true).toString();
repository.closeSession();
}
catch (SVNException e) {
throw new VcsException(e);
} finally {
if (repository != null) {
repository.closeSession();
}
}
final MergeTrackerProxy proxy = new MergeTrackerProxy(new Consumer<TreeStructureNode<SVNLogEntry>>() {
@@ -356,7 +369,17 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
revisionBefore = SVNRevision.create(changeTo.longValue());
}
else {
revisionBefore = SVNRevision.create(myVcs.createRepository(url).getLatestRevision());
SVNRepository repository = null;
final long revision;
try {
repository = myVcs.createRepository(url);
revision = repository.getLatestRevision();
} finally {
if (repository != null) {
repository.closeSession();
}
}
revisionBefore = SVNRevision.create(revision);
}
final SVNRevision revisionAfter;
if (dateFrom != null) {
@@ -20,10 +20,10 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnConfiguration;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.io.SVNRepository;
@@ -131,14 +131,18 @@ public class SvnIntegrateEnvironment extends AbstractSvnUpdateIntegrateEnvironme
}
else {
SVNRepository repos = null;
try {
SVNRepository repos = myVcs.createRepository(svnURL2.toString());
repos = myVcs.createRepository(svnURL2.toString());
final long latestRev = repos.getLatestRevision();
repos.closeSession();
return String.valueOf(latestRev);
}
catch (SVNException e) {
return null;
} finally {
if (repos != null) {
repos.closeSession();
}
}
}
}
@@ -162,7 +162,7 @@ public class DomElementsErrorPanel extends JPanel implements CommittablePanel, H
}
@Override
protected void fillDaemonCodeAnalyzerErrorsSatus(DaemonCodeAnalyzerStatus status, boolean fillErrorsCount) {
protected void fillDaemonCodeAnalyzerErrorsStatus(DaemonCodeAnalyzerStatus status, boolean fillErrorsCount) {
for (int i = 0; i < status.errorCount.length; i++) {
final HighlightSeverity minSeverity = SeverityRegistrar.getInstance(myProject).getSeverityByIndex(i);
if (minSeverity == null) {