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

This commit is contained in:
Kirill Kalishev
2010-11-11 13:45:41 +03:00
136 changed files with 2385 additions and 2044 deletions
@@ -97,7 +97,9 @@ public class SmartStepIntoActionHandler extends DebuggerActionHandler {
}
final Document doc = FileDocumentManager.getInstance().getDocument(vFile);
if (line >= doc.getLineCount()) {
return Collections.emptyList(); // the document has been changed
}
final int startOffset = doc.getLineStartOffset(line);
final TextRange lineRange = new TextRange(startOffset, doc.getLineEndOffset(line));
final int offset = CharArrayUtil.shiftForward(doc.getCharsSequence(), startOffset, " \t");
@@ -505,7 +505,7 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
if (thisObjectReference != null && evaluationContext.getDebugProcess().getVirtualMachineProxy().canGetSyntheticAttribute()) {
final ReferenceType thisRefType = thisObjectReference.referenceType();
if (thisRefType instanceof ClassType && thisRefType.name().contains("$")) { // makes sense for nested classes only
if (thisRefType instanceof ClassType && thisRefType.equals(location.declaringType()) && thisRefType.name().contains("$")) { // makes sense for nested classes only
final ClassType clsType = (ClassType)thisRefType;
for (Field field : clsType.fields()) {
if (field.isSynthetic() && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
@@ -21,12 +21,14 @@ import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
import com.intellij.debugger.engine.jdi.StackFrameProxy;
import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
import com.intellij.debugger.ui.tree.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
@@ -171,8 +173,16 @@ public class ClassRenderer extends NodeRendererImpl{
return false;
}
if (isSynthetic) {
if (objInstance.equals(context.getThisObject()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
return false;
try {
final StackFrameProxy frameProxy = context.getFrameProxy();
if (frameProxy != null) {
final Location location = frameProxy.location();
if (location != null && objInstance.equals(context.getThisObject()) && Comparing.equal(objInstance.referenceType(), location.declaringType()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
return false;
}
}
}
catch (EvaluateException ignored) {
}
}
if(!SHOW_STATIC && field.isStatic()) {
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.roots.ui.configuration;
import com.intellij.ide.ui.ListCellRendererWrapper;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
@@ -22,7 +23,6 @@ import com.intellij.openapi.ui.ComboBox;
import com.intellij.pom.java.LanguageLevel;
import javax.swing.*;
import java.awt.*;
/**
* @author ven
@@ -34,30 +34,27 @@ public class LanguageLevelCombo extends ComboBox {
for (LanguageLevel level : LanguageLevel.values()) {
addItem(level);
}
setRenderer(new MyDefaultListCellRenderer());
setRenderer(new ListCellRendererWrapper(getRenderer()) {
@Override
public void customize(final JList list, final Object value, final int index, final boolean selected, final boolean hasFocus) {
if (value instanceof LanguageLevel) {
setText(((LanguageLevel)value).getPresentableText());
}
else if (value instanceof String) {
setText((String)value);
}
}
});
}
public void reset(Project project){
public void reset(Project project) {
setSelectedItem(LanguageLevelProjectExtension.getInstance(project).getLanguageLevel());
}
public void setSelectedItem(Object anObject) {
if (anObject == null){
if (anObject == null) {
anObject = USE_PROJECT_LANGUAGE_LEVEL;
}
super.setSelectedItem(anObject);
}
private static class MyDefaultListCellRenderer extends DefaultListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof LanguageLevel) {
setText(((LanguageLevel)value).getPresentableText());
}
else if (value instanceof String) {
setText((String)value);
}
return this;
}
}
}
@@ -108,7 +108,6 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable {
myCbProjectJdk.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (myFreeze) return;
final Sdk oldJdk = myJdksModel.getProjectSdk();
myJdksModel.setProjectSdk(myCbProjectJdk.getSelectedJdk());
clearCaches();
}
@@ -20,8 +20,6 @@ import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.template.SmartCompletionContextType;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Computable;
import com.intellij.patterns.PsiJavaPatterns;
import com.intellij.psi.*;
import com.intellij.psi.filters.getters.ClassLiteralGetter;
@@ -52,17 +50,13 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet
}
public static LookupElement createKeywordLookupItem(final PsiElement element, final String s) {
return ApplicationManager.getApplication().runReadAction(new Computable<LookupItem>() {
public LookupItem compute() {
try {
final PsiKeyword keyword = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createKeyword(s);
return new KeywordLookupItem(keyword, element).setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
}
catch (IncorrectOperationException e) {
throw new RuntimeException(e);
}
}
});
try {
final PsiKeyword keyword = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createKeyword(s);
return new KeywordLookupItem(keyword, element).setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
}
catch (IncorrectOperationException e) {
throw new RuntimeException(e);
}
}
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.codeInsight.lookup.LookupItemUtil;
import com.intellij.codeInsight.lookup.TailTypeDecorator;
import com.intellij.psi.*;
import com.intellij.psi.filters.ContextGetter;
import com.intellij.util.IncorrectOperationException;
@@ -32,6 +33,45 @@ import java.util.Set;
*/
public class JavaAwareCompletionData extends CompletionData{
@NotNull
static TailType analyzeItem(final Object completion, final PsiElement position) {
if(completion instanceof PsiKeyword){
final String text = ((PsiKeyword)completion).getText();
if(PsiKeyword.BREAK.equals(text) || PsiKeyword.CONTINUE.equals(text)) {
PsiElement scope = position;
while(true){
if (scope instanceof PsiFile || scope instanceof PsiMethod || scope instanceof PsiClassInitializer){
return TailType.SEMICOLON;
}
if (scope instanceof PsiLabeledStatement){
return TailType.NONE;
}
scope = scope.getParent();
}
}
if(PsiKeyword.RETURN.equals(text)){
PsiElement scope = position;
while(true){
if (scope instanceof PsiFile || scope instanceof PsiClassInitializer){
return TailType.NONE;
}
if (scope instanceof PsiMethod){
final PsiMethod method = (PsiMethod)scope;
if(method.isConstructor() || PsiType.VOID.equals(method.getReturnType())) {
return TailType.SEMICOLON;
}
return TailType.SPACE;
}
scope = scope.getParent();
}
}
}
return TailType.NONE;
}
protected void addLookupItem(Set<LookupElement> set, TailType tailType, @NotNull Object completion, final PsiFile file, final CompletionVariant variant) {
if (completion instanceof LookupElement && !(completion instanceof LookupItem)) {
set.add((LookupElement)completion);
@@ -44,18 +84,29 @@ public class JavaAwareCompletionData extends CompletionData{
LookupItem ret = (LookupItem)_ret;
final InsertHandler insertHandler = variant.getInsertHandler();
if(insertHandler != null && ret.getInsertHandler() == null) {
ret.setInsertHandler(insertHandler);
ret.setTailType(TailType.UNKNOWN);
}
else if (tailType != TailType.NONE) {
ret.setTailType(tailType);
}
ret.setInsertHandler(new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
final TailType type = analyzeItem(item.getObject(), context.getFile().findElementAt(context.getStartOffset()));
new DefaultInsertHandler().handleInsert(context, item);
if (type != TailType.NONE) {
context.setAddCompletionChar(false);
type.processTail(context.getEditor(), context.getTailOffset());
}
}
});
final Map<Object, Object> itemProperties = variant.getItemProperties();
for (final Object key : itemProperties.keySet()) {
ret.setAttribute(key, itemProperties.get(key));
}
set.add(ret);
if ((insertHandler == null || ret.getInsertHandler() != null) && tailType != TailType.NONE) {
set.add(TailTypeDecorator.withTail(ret, tailType));
} else {
set.add(ret);
}
}
protected void addKeywords(final Set<LookupElement> set, final PsiElement position, final PrefixMatcher matcher, final PsiFile file,
@@ -16,7 +16,6 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.TailTypes;
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix;
import com.intellij.codeInsight.hint.ShowParameterInfoHandler;
import com.intellij.codeInsight.lookup.LookupElement;
@@ -250,15 +249,6 @@ public class JavaCompletionContributor extends CompletionContributor {
completionData.fillCompletions(parameters, result);
for (final LookupElement item : lookupSet) {
if (item instanceof LookupItem && ((LookupItem)item).getInsertHandler() == null) {
((LookupItem)item).setInsertHandler(new InsertHandler() {
public void handleInsert(final InsertionContext context, final LookupElement item) {
analyzeItem((LookupItem)item, item.getObject(), parameters.getPosition());
new DefaultInsertHandler().handleInsert(context, item);
}
});
}
result.addElement(item);
}
@@ -469,54 +459,6 @@ public class JavaCompletionContributor extends CompletionContributor {
return parent.getParent() instanceof PsiTypeElement || parent.getParent() instanceof PsiExpressionStatement || parent.getParent() instanceof PsiReferenceList;
}
public static void analyzeItem(final LookupItem item, final Object completion, final PsiElement position) {
if(completion instanceof PsiKeyword){
if(PsiKeyword.BREAK.equals(((PsiKeyword)completion).getText())
|| PsiKeyword.CONTINUE.equals(((PsiKeyword)completion).getText())){
PsiElement scope = position;
while(true){
if (scope instanceof PsiFile
|| scope instanceof PsiMethod
|| scope instanceof PsiClassInitializer){
item.setTailType(TailType.SEMICOLON);
break;
}
else if (scope instanceof PsiLabeledStatement){
item.setTailType(TailType.NONE);
break;
}
scope = scope.getParent();
}
}
if(PsiKeyword.RETURN.equals(((PsiKeyword)completion).getText())){
PsiElement scope = position;
while(true){
if (scope instanceof PsiFile
|| scope instanceof PsiClassInitializer){
item.setTailType(TailType.NONE);
break;
}
else if (scope instanceof PsiMethod){
final PsiMethod method = (PsiMethod)scope;
if(method.isConstructor() || PsiType.VOID.equals(method.getReturnType())) {
item.setTailType(TailType.SEMICOLON);
}
else item.setTailType(TailType.SPACE);
break;
}
scope = scope.getParent();
}
}
if(PsiKeyword.SYNCHRONIZED.equals(((PsiKeyword)completion).getText())){
if (PsiTreeUtil.getParentOfType(position, PsiMember.class, PsiCodeBlock.class) instanceof PsiCodeBlock){
item.setTailType(TailTypes.SYNCHRONIZED_LPARENTH);
}
}
}
}
public void beforeCompletion(@NotNull final CompletionInitializationContext context) {
final PsiFile file = context.getFile();
@@ -541,6 +541,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
variant.addCompletion(PsiKeyword.RETURN, TailType.SPACE);
variant.addCompletion(PsiKeyword.NEW, TailType.SPACE);
variant.addCompletion(PsiKeyword.ASSERT, TailType.SPACE);
variant.addCompletion(PsiKeyword.SYNCHRONIZED, TailTypes.SYNCHRONIZED_LPARENTH);
}
@Override
@@ -68,7 +68,7 @@ public class ModifierChooser
});
myMap.put(new OrFilter(new ClassFilter(PsiStatement.class), new ClassFilter(PsiCodeBlock.class)), new String[][]{
new String[]{"final", "synchronized"}
new String[]{"final"}
});
myMap.put(new ClassFilter(PsiParameterList.class), new String[][]{
@@ -399,7 +399,7 @@ public class HighlightClassUtil {
static HighlightInfo checkExtendsClassAndImplementsInterface(PsiReferenceList referenceList,
JavaResolveResult resolveResult,
PsiJavaCodeReferenceElement context) {
PsiJavaCodeReferenceElement ref) {
PsiClass aClass = (PsiClass)referenceList.getParent();
boolean isImplements = referenceList.equals(aClass.getImplementsList());
boolean isInterface = aClass.isInterface();
@@ -409,10 +409,10 @@ public class HighlightClassUtil {
PsiClass extendFrom = (PsiClass)resolveResult.getElement();
if (extendFrom.isInterface() != mustBeInterface) {
errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
context,
ref,
mustBeInterface ? INTERFACE_EXPECTED : NO_INTERFACE_EXPECTED);
PsiClassType type =
JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor());
JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(ref);
QuickFixAction.registerQuickFixAction(errorResult, new ChangeExtendsToImplementsFix(aClass, type));
}
return errorResult;
@@ -98,7 +98,7 @@ public abstract class CreateConstructorFromThisOrSuperFix extends CreateFromUsag
targetClass = constructor.getContainingClass();
myMethodCall = CodeInsightUtil.findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(), myMethodCall.getClass());
((RangeMarkerEx)rangeMarker).dispose();
rangeMarker.dispose();
Template template = templateBuilder.buildTemplate();
final Editor editor = positionCursor(project, targetClass.getContainingFile(), targetClass);
@@ -229,7 +229,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
Template template = builder.buildTemplate();
newEditor.getCaretModel().moveToOffset(rangeMarker.getStartOffset());
newEditor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset());
((RangeMarkerEx)rangeMarker).dispose();
rangeMarker.dispose();
if (!shouldBeAbstract) {
startTemplate(newEditor, template, project, new TemplateEditingAdapter() {
@@ -357,9 +357,9 @@ public class DeclarationParser {
@NotNull
private static PsiBuilder.Marker parseTypeNotNull(final PsiBuilder builder) {
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
assert typeInfo != null : builder.getOriginalText();
return typeInfo.marker;
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
assert type != null : builder.getOriginalText();
return type;
}
@NotNull
@@ -399,14 +399,7 @@ public class DeclarationParser {
final boolean anno, final boolean constructor) {
parseParameterList(builder);
if (constructor && builder.getTokenType() == JavaTokenType.LBRACKET) {
final PsiBuilder.Marker marker = builder.mark();
eatBrackets(builder, false);
marker.error(JavaErrorMessages.message("expected.semicolon"));
}
else {
eatBrackets(builder, true);
}
eatBrackets(builder, constructor, JavaErrorMessages.message("expected.semicolon"));
if (areTypeAnnotationsSupported(builder)) {
final PsiBuilder.Marker receiver = builder.mark();
@@ -544,21 +537,23 @@ public class DeclarationParser {
final PsiBuilder.Marker param = builder.mark();
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
final PsiBuilder.Marker type = ellipsis ? ReferenceParser.parseTypeWithEllipsis(builder, true, true) :
ReferenceParser.parseType(builder, true, true, false);
if (type == null && modListInfo.second) {
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags);
if (typeInfo == null && modListInfo.second) {
param.rollbackTo();
return null;
}
if (type == null) {
if (typeInfo == null) {
error(builder, JavaErrorMessages.message("expected.type"));
emptyElement(builder, JavaElementType.TYPE);
}
if (expect(builder, JavaTokenType.IDENTIFIER)) {
eatBrackets(builder, true);
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
done(param, JavaElementType.PARAMETER);
return param;
}
@@ -593,7 +588,7 @@ public class DeclarationParser {
while (true) {
shouldRollback = true;
if (!eatBrackets(builder, true)) {
if (!eatBrackets(builder, false, null)) {
unclosed = true;
}
@@ -655,14 +650,25 @@ public class DeclarationParser {
return declaration;
}
private static boolean eatBrackets(final PsiBuilder builder, final boolean withError) {
private static boolean eatBrackets(final PsiBuilder builder, final boolean isError, @Nullable final String error) {
if (builder.getTokenType() != JavaTokenType.LBRACKET) return true;
final PsiBuilder.Marker marker = isError ? builder.mark() : null;
boolean result = true;
while (expect(builder, JavaTokenType.LBRACKET)) {
if (!expect(builder, JavaTokenType.RBRACKET)) {
if (withError) error(builder, JavaErrorMessages.message("expected.rbracket"));
return false;
if (!isError) error(builder, JavaErrorMessages.message("expected.rbracket"));
result = false;
break;
}
}
return true;
if (marker != null) {
marker.error(error);
}
return result;
}
@Nullable
@@ -161,8 +161,7 @@ public class ExpressionParser {
return parseUnary(builder);
case TYPE:
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
return typeInfo != null ? typeInfo.marker : null;
return ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
default:
assert false : "Unexpected type: " + type;
@@ -255,7 +254,7 @@ public class ExpressionParser {
final PsiBuilder.Marker typeCast = builder.mark();
builder.advanceLexer();
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
if (typeInfo == null || builder.getTokenType() != JavaTokenType.RPARENTH) {
typeCast.rollbackTo();
@@ -733,8 +732,7 @@ public class ExpressionParser {
private static PsiBuilder.Marker parseClassObjectAccess(final PsiBuilder builder) {
final PsiBuilder.Marker expr = builder.mark();
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, false, false, false);
if (type == null) {
if (ReferenceParser.parseType(builder, 0) == null) {
expr.drop();
return null;
}
@@ -32,10 +32,16 @@ import static com.intellij.lang.java.parser.JavaParserUtil.emptyElement;
public class ReferenceParser {
public static final int EAT_LAST_DOT = 0x01;
public static final int ELLIPSIS = 0x02;
public static final int WILDCARD = 0x04;
public static final int DIAMONDS = 0x08;
public static class TypeInfo {
public boolean isPrimitive = false;
public boolean isParameterized = false;
public boolean isArray = false;
public boolean isVarArg = false;
public boolean hasErrors = false;
public PsiBuilder.Marker marker = null;
}
@@ -45,33 +51,19 @@ public class ReferenceParser {
private ReferenceParser() { }
@Nullable
public static TypeInfo parseType(final PsiBuilder builder) {
return parseTypeWithInfo(builder, true, true, false);
}
@Nullable
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean diamonds) {
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard, diamonds);
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final int flags) {
final TypeInfo typeInfo = parseTypeInfo(builder, flags);
return typeInfo != null ? typeInfo.marker : null;
}
@Nullable
public static PsiBuilder.Marker parseTypeWithEllipsis(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard, false);
if (typeInfo == null) return null;
PsiBuilder.Marker type = typeInfo.marker;
if (builder.getTokenType() == JavaTokenType.ELLIPSIS) {
type = typeInfo.marker.precede();
builder.advanceLexer();
type.done(JavaElementType.TYPE);
}
return type;
public static TypeInfo parseTypeInfo(final PsiBuilder builder, final int flags) {
return parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS));
}
@Nullable
private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean diamonds) {
private static TypeInfo parseTypeInfo(final PsiBuilder builder,
final boolean eatLastDot, final boolean wildcard, final boolean diamonds, final boolean ellipsis) {
if (builder.getTokenType() == null) return null;
final TypeInfo typeInfo = new TypeInfo();
@@ -126,18 +118,28 @@ public class ReferenceParser {
type = type.precede();
}
if (ellipsis && builder.getTokenType() == JavaTokenType.ELLIPSIS) {
type = type.precede();
builder.advanceLexer();
type.done(JavaElementType.TYPE);
typeInfo.isVarArg = true;
}
typeInfo.marker = type;
return typeInfo;
}
private static boolean isSet(final int mask, final int flag) {
return (mask & flag) != 0;
}
@NotNull
private static PsiBuilder.Marker parseWildcardType(final PsiBuilder builder) {
final PsiBuilder.Marker type = builder.mark();
builder.advanceLexer();
if (expect(builder, WILDCARD_KEYWORD_SET)) {
final PsiBuilder.Marker boundType = parseType(builder, true, false, false);
if (boundType == null) {
if (parseTypeInfo(builder, EAT_LAST_DOT) == null) {
error(builder, JavaErrorMessages.message("expected.type"));
}
}
@@ -248,8 +250,7 @@ public class ReferenceParser {
boolean isOk = true;
while (true) {
final PsiBuilder.Marker type = parseType(builder, true, wildcard, diamonds);
if (type == null) {
if (parseTypeInfo(builder, true, wildcard, diamonds, false) == null) {
error(builder, JavaErrorMessages.message("expected.identifier"));
}
@@ -232,7 +232,7 @@ public class StatementParser {
final PsiBuilder.Marker declStatement = builder.mark();
final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK);
if (decl == null) {
ReferenceParser.parseType(builder, false, false, false);
ReferenceParser.parseType(builder, 0);
error(builder, JavaErrorMessages.message("expected.identifier"));
}
done(declStatement, JavaElementType.DECLARATION_STATEMENT);
@@ -253,8 +253,8 @@ public interface JavaElementType {
return JavaParserUtil.parseFragment(chameleon,
new JavaParserUtil.ParserWrapper() {
public void parse(final PsiBuilder builder) {
ReferenceParser.parseType(builder);
expect(builder, JavaTokenType.ELLIPSIS);
ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
expect(builder, JavaTokenType.ELLIPSIS); // todo[r.sh] parse ellipsis and fix PsiTypeCodeFragmentImpl.getType()
}
});
}
@@ -26,8 +26,10 @@ package com.intellij.refactoring.introduceVariable;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.highlighting.HighlightManager;
import com.intellij.codeInsight.intention.impl.TypeExpression;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.codeInsight.template.*;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.lang.LanguageRefactoringSupport;
@@ -463,6 +465,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
getSettings(project, editor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, choice);
if (!settings.isOK()) return;
typeSelectorManager.setAllOccurences(choice != OccurrencesChooser.ReplaceChoice.NO);
final TypeExpression expression = new TypeExpression(project, typeSelectorManager.getTypesForAll());
final RangeMarker exprMarker = editor.getDocument().createRangeMarker(expr.getTextRange());
final SuggestedNameInfo suggestedName = getSuggestedName(settings.getSelectedType(), expr);
final Runnable runnable =
@@ -482,8 +485,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
@Override
protected void addAdditionalVariables(TemplateBuilderImpl builder) {
final PsiTypeElement typeElement = elementToRename.getTypeElement();
builder.replaceElement(typeElement, "Variable_Type", ReassignVariableUtil
.createExpression(typeSelectorManager, typeElement.getText()), false, true);
builder.replaceElement(typeElement, "Variable_Type",
ReassignVariableUtil.createExpression(expression, typeElement.getText()), false, true);
}
};
renamer.setAdvertisementText(
@@ -12,6 +12,7 @@
*/
package com.intellij.refactoring.introduceVariable;
import com.intellij.codeInsight.intention.impl.TypeExpression;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
@@ -29,6 +30,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
@@ -151,30 +153,6 @@ public class ReassignVariableUtil {
}
}
static Expression createExpression(final TypeSelectorManagerImpl typeSelectorManager, final String defaultText) {
final PsiType[] types = typeSelectorManager.getTypesForAll();
return new Expression() {
@Override
public com.intellij.codeInsight.template.Result calculateResult(ExpressionContext context) {
return new TextResult(defaultText);
}
@Override
public com.intellij.codeInsight.template.Result calculateQuickResult(ExpressionContext context) {
return new TextResult(defaultText);
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
LookupElement[] result = new LookupElement[types.length];
for (int i = 0, typesLength = types.length; i < typesLength; i++) {
result[i] = PsiTypeLookupItem.createLookupItem(types[i], null);
}
return result;
}
};
}
@Nullable
static String getAdvertisementText(Editor editor, PsiDeclarationStatement declaration, PsiType type, PsiType[] typesForAll) {
final VariablesProcessor processor = findVariablesOfType(editor, declaration, type);
@@ -187,4 +165,23 @@ public class ReassignVariableUtil {
}
return typesForAll.length > 1 ? "Press Shift Tab to change type" : null;
}
public static Expression createExpression(final TypeExpression expression, final String defaultType) {
return new Expression() {
@Override
public com.intellij.codeInsight.template.Result calculateResult(ExpressionContext context) {
return new TextResult(defaultType);
}
@Override
public com.intellij.codeInsight.template.Result calculateQuickResult(ExpressionContext context) {
return new TextResult(defaultType);
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
return expression.calculateLookupItems(context);
}
};
}
}
@@ -124,6 +124,33 @@ public class PullUpHelper extends BaseRefactoringProcessor{
if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, movedMembers, myTargetSuperClass, mySourceClass)) {
PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true);
}
if (modifierListOwner instanceof PsiClass) {
modifierListOwner.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitMethod(PsiMethod method) {
check(method);
}
@Override
public void visitField(PsiField field) {
check(field);
}
@Override
public void visitClass(PsiClass aClass) {
check(aClass);
super.visitClass(aClass);
}
private void check(PsiMember member) {
if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
if (willBeUsedInSubclass(member, movedMembers, myTargetSuperClass, mySourceClass)) {
PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true);
}
}
}
});
}
}
ChangeContextUtil.encodeContextInfo(info.getMember(), true);
}
@@ -38,6 +38,7 @@ import java.util.*;
* @author dsl
*/
public class TypeSelectorManagerImpl implements TypeSelectorManager {
private SmartTypePointer myPointer;
private PsiType myDefaultType;
private final PsiExpression myMainOccurence;
private final PsiExpression[] myOccurrences;
@@ -46,6 +47,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
private final boolean myIsOneSuggestion;
private TypeSelector myTypeSelector;
private final PsiElementFactory myFactory;
private final SmartTypePointerManager mySmartTypePointerManager;
private ExpectedTypesProvider.ExpectedClassProvider myOccurrenceClassProvider;
private ExpectedTypesProvider myExpectedTypesProvider;
@@ -59,7 +61,8 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression[] occurrences, boolean areTypesDirected) {
myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
myDefaultType = type;
mySmartTypePointerManager = SmartTypePointerManager.getInstance(project);
setDefaultType(type);
myMainOccurence = null;
myOccurrences = occurrences;
myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
@@ -83,7 +86,8 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
PsiExpression mainOccurence,
PsiExpression[] occurrences) {
myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
myDefaultType = type;
mySmartTypePointerManager = SmartTypePointerManager.getInstance(project);
setDefaultType(type);
myMainOccurence = mainOccurence;
myOccurrences = occurrences;
myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
@@ -94,7 +98,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
if (containingMethod != null) {
if (PsiUtil.resolveClassInType(type) != null) {
myDefaultType = checkIfTypeAccessible(type, project, containingMethod);
setDefaultType(checkIfTypeAccessible(type, project, containingMethod));
}
}
@@ -132,7 +136,15 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
}
public PsiType getDefaultType() {
return myDefaultType;
if (myDefaultType.isValid()) {
return myDefaultType;
}
return myPointer.getType();
}
public void setDefaultType(PsiType defaultType) {
myDefaultType = defaultType;
myPointer = mySmartTypePointerManager.createSmartTypePointer(defaultType);
}
private ExpectedTypesProvider.ExpectedClassProvider createOccurrenceClassProvider() {
@@ -151,7 +163,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(myMainOccurence, false, myOccurrenceClassProvider,
false);
final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
RefactoringHierarchyUtil.processSuperTypes(myDefaultType, new RefactoringHierarchyUtil.SuperTypeVisitor() {
RefactoringHierarchyUtil.processSuperTypes(getDefaultType(), new RefactoringHierarchyUtil.SuperTypeVisitor() {
public void visitType(PsiType aType) {
checkIfAllowed(aType);
}
@@ -193,7 +205,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
}
final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
RefactoringHierarchyUtil.processSuperTypes(myDefaultType, new RefactoringHierarchyUtil.SuperTypeVisitor() {
RefactoringHierarchyUtil.processSuperTypes(getDefaultType(), new RefactoringHierarchyUtil.SuperTypeVisitor() {
public void visitType(PsiType aType) {
checkIfAllowed(aType);
}
@@ -234,18 +246,18 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
for (int index = 0; index < result.size(); index++) {
PsiType psiType = result.get(index);
if (psiType.equals(myDefaultType)) {
if (psiType.equals(getDefaultType())) {
result.remove(index);
break;
}
}
final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(myDefaultType);
final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(getDefaultType());
if (unboxedType != null) {
result.remove(unboxedType);
result.add(0, unboxedType);
}
result.add(0, myDefaultType);
result.add(0, getDefaultType());
return result;
}
@@ -292,7 +304,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
}
private String getStatsKey() {
return "IntroduceVariable##" + serialize(myDefaultType);
return "IntroduceVariable##" + serialize(getDefaultType());
}
private String serialize(PsiType type) {
@@ -0,0 +1,8 @@
public class Foooo {
{
int intaaaa;
for (in<caret>)
}
}
@@ -0,0 +1,8 @@
public class Foooo {
{
int intaaaa;
for (int <caret>)
}
}
@@ -0,0 +1,9 @@
// "Change 'implements b' to 'extends b'" "true"
class a extends b<C.D> {
}
class b<T> {}
class C {
static class D {}
}
@@ -0,0 +1,9 @@
// "Change 'implements b' to 'extends b'" "true"
class a implements <caret>b<C.D> {
}
class b<T> {}
class C {
static class D {}
}
@@ -0,0 +1,32 @@
PsiJavaFile:VarArgBrackets.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:foo
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:foo('foo')
PsiParameterList:(int... x[])
PsiJavaToken:LPARENTH('(')
PsiParameter:x
PsiModifierList:
<empty list>
PsiTypeElement:int...
PsiTypeElement:int
PsiKeyword:int('int')
PsiJavaToken:ELLIPSIS('...')
PsiWhiteSpace(' ')
PsiIdentifier:x('x')
PsiErrorElement:')' expected
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,15 @@
public class B extends A {
private void f(){
new C();
}
<caret>
private static class C{
private C(){
}
}
}
//A.java
class A {
}
@@ -0,0 +1,15 @@
public class B extends A {
private void f(){
new C();
}
}
//A.java
class A {
protected static class C{
protected C(){
}
}
}
@@ -620,6 +620,12 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase {
public void testPrimitiveTypesInForLoop5() throws Throwable { doPrimitiveTypeTest() }
public void testPrimitiveTypesInForLoop6() throws Throwable { doPrimitiveTypeTest() }
public void testPrimitiveTypesInForLoopSpace() throws Throwable {
configure()
myFixture.type ' '
checkResultByFile(getTestName(false) + "_after.java")
}
public void testSecondInvocationToFillCommonPrefix() throws Throwable {
configure()
type('a');
@@ -90,6 +90,7 @@ public class DeclarationParserTest extends JavaParsingTestCase {
public void testUnclosed4() { doParserTest("{ void f(int a,, }", false, false); }
public void testUnclosed5() { doParserTest("{ void f(int a,); }", false, false); }
public void testConstructorBrackets() { doParserTest("{ A() [] { } }", false, false); }
public void testVarArgBrackets() { doParserTest("{ void foo(int... x[]); }", false, false); }
public void testGenericMethod() { doParserTest("{ public static <E> test();\n" +
" <E> void test1();\n" +
@@ -30,18 +30,18 @@ public class ReferenceParserTest extends JavaParsingTestCase {
public void testReference1() { doRefParserTest("a.", true); }
public void testReference2() { doRefParserTest("a.b", false); }
public void testType0() { doTypeParserTest("int", false); }
public void testType1() { doTypeParserTest("a.b", false); }
public void testType2() { doTypeParserTest("int[]", false); }
public void testType3() { doTypeParserTest("int[][", false); }
public void testType4() { doTypeParserTest("Map<String,List<String>>", false); }
public void testType5() { doTypeParserTest("Object[]...", false); }
public void testType0() { doTypeParserTest("int"); }
public void testType1() { doTypeParserTest("a.b"); }
public void testType2() { doTypeParserTest("int[]"); }
public void testType3() { doTypeParserTest("int[]["); }
public void testType4() { doTypeParserTest("Map<String,List<String>>"); }
public void testType5() { doTypeParserTest("Object[]..."); }
public void testType6() {
withLevel(LanguageLevel.JDK_1_7,
new Runnable() { @Override
public void run() { doTypeParserTest("@English String @NonEmpty []", false); } });
public void run() { doTypeParserTest("@English String @NonEmpty []"); } });
}
public void testType7() { doTypeParserTest("Diamond<>", true); }
public void testType7() { doTypeParserTest("Diamond<>"); }
public void testTypeParams0() { doTypeParamsParserTest("<T>"); }
public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); }
@@ -61,14 +61,11 @@ public class ReferenceParserTest extends JavaParsingTestCase {
});
}
private void doTypeParserTest(final String text, final boolean diamonds) {
private void doTypeParserTest(final String text) {
doParserTest(text, new TestParser() {
@Override
public void parse(final PsiBuilder builder) {
if (diamonds)
ReferenceParser.parseType(builder, false, false, true);
else
ReferenceParser.parseTypeWithEllipsis(builder, false, false);
ReferenceParser.parseType(builder, ReferenceParser.DIAMONDS | ReferenceParser.ELLIPSIS);
}
});
}
@@ -42,6 +42,10 @@ public class PullUpTest extends LightCodeInsightTestCase {
doTest(new RefactoringTestUtil.MemberDescriptor("C", PsiClass.class),
new RefactoringTestUtil.MemberDescriptor("D", PsiClass.class));
}
public void testPullUpPrivateInnerClassWithPrivateConstructor() throws Exception {
doTest(new RefactoringTestUtil.MemberDescriptor("C", PsiClass.class));
}
public void testPullUpAndAbstractize() throws Exception {
doTest(new RefactoringTestUtil.MemberDescriptor("a", PsiMethod.class),
@@ -140,13 +140,9 @@ public abstract class CompletionService {
getVariantsFromContributors(parameters, null, new Consumer<LookupElement>() {
public void consume(final LookupElement lookupElement) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (lookupSet.add(lookupElement)) {
consumer.consume(lookupElement);
}
}
});
if (lookupSet.add(lookupElement)) {
consumer.consume(lookupElement);
}
}
});
return lookupSet.toArray(new LookupElement[lookupSet.size()]);
@@ -230,7 +230,8 @@ public class PsiTreeUtil {
}
};
PsiTreeUtil.processElements(element, processor);
processElements(element, processor);
//noinspection unchecked
return (T)processor.getFoundElement();
}
@@ -238,7 +239,8 @@ public class PsiTreeUtil {
public static <T extends PsiElement> T getChildOfType(@Nullable PsiElement element, @NotNull Class<T> aClass) {
if (element == null) return null;
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
if (instanceOf(child, aClass)) {
if (aClass.isInstance(child)) {
//noinspection unchecked
return (T)child;
}
}
@@ -258,8 +260,9 @@ public class PsiTreeUtil {
List<T> result = null;
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
if (instanceOf(child, aClass)) {
if (aClass.isInstance(child)) {
if (result == null) result = new SmartList<T>();
//noinspection unchecked
result.add((T)child);
}
}
@@ -272,29 +275,16 @@ public class PsiTreeUtil {
List<T> result = new SmartList<T>();
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
if (instanceOf(child, aClass)) {
if (aClass.isInstance(child)) {
//noinspection unchecked
result.add((T)child);
}
}
return result;
}
private static boolean instanceOf(final PsiElement child, final Class... classes) {
/*
if (aClass == PsiClass.class) return child instanceof PsiClass;
else if (aClass == PsiMethod.class) return child instanceof PsiMethod;
else if (aClass == PsiField.class) return child instanceof PsiField;
else if (aClass == PsiMember.class) return child instanceof PsiMember;
else if (aClass == PsiDocCommentOwner.class) return child instanceof PsiDocCommentOwner;
else if (aClass == PsiStatement.class) return child instanceof PsiStatement;
else if (aClass == PsiCodeBlock.class) return child instanceof PsiCodeBlock;
else if (aClass == PsiClassInitializer.class) return child instanceof PsiClassInitializer;
else if (aClass == XmlTag.class) return child instanceof XmlTag;
else if (aClass == XmlDocument.class) return child instanceof XmlDocument;
*/
for (Class each : classes) {
private static boolean instanceOf(final PsiElement child, final Class<?>... classes) {
for (final Class<?> each : classes) {
if (each.isInstance(child)) return true;
}
return false;
@@ -313,7 +303,10 @@ public class PsiTreeUtil {
if (element == null) return null;
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
for (Class<? extends T> aClass : classes) {
if (instanceOf(child, aClass)) return (T)child;
if (aClass.isInstance(child)) {
//noinspection unchecked
return (T)child;
}
}
}
return null;
@@ -323,7 +316,10 @@ public class PsiTreeUtil {
public static <T extends PsiElement> T getNextSiblingOfType(@Nullable PsiElement sibling, @NotNull Class<T> aClass) {
if (sibling == null) return null;
for (PsiElement child = sibling.getNextSibling(); child != null; child = child.getNextSibling()) {
if (instanceOf(child, aClass)) return (T)child;
if (aClass.isInstance(child)) {
//noinspection unchecked
return (T)child;
}
}
return null;
}
@@ -332,7 +328,10 @@ public class PsiTreeUtil {
public static <T extends PsiElement> T getPrevSiblingOfType(@Nullable PsiElement sibling, @NotNull Class<T> aClass) {
if (sibling == null) return null;
for (PsiElement child = sibling.getPrevSibling(); child != null; child = child.getPrevSibling()) {
if (instanceOf(child, aClass)) return (T)child;
if (aClass.isInstance(child)) {
//noinspection unchecked
return (T)child;
}
}
return null;
}
@@ -391,11 +390,12 @@ public class PsiTreeUtil {
element = element.getContext();
}
while (element != null && !instanceOf(element, aClass)) {
while (element != null && !aClass.isInstance(element)) {
if (instanceOf(element, stopAt)) return null;
element = element.getContext();
}
//noinspection unchecked
return (T)element;
}
@@ -424,6 +424,7 @@ public class PsiTreeUtil {
element = element.getContext();
}
//noinspection unchecked
return (T)element;
}
@@ -435,7 +436,8 @@ public class PsiTreeUtil {
}
while (element != null) {
if (instanceOf(element, aClass)) {
if (aClass.isInstance(element)) {
//noinspection unchecked
return (T)element;
}
if (element instanceof PsiFile) return null;
@@ -455,12 +457,13 @@ public class PsiTreeUtil {
element = element.getParent();
}
while (element != null && !instanceOf(element, aClass)) {
while (element != null && !aClass.isInstance(element)) {
if (instanceOf(element, stopAt)) return null;
if (element instanceof PsiFile) return null;
element = element.getParent();
}
//noinspection unchecked
return (T)element;
}
@@ -509,7 +512,10 @@ public class PsiTreeUtil {
public static <T extends PsiElement> T getNonStrictParentOfType(@NotNull PsiElement element, @NotNull Class<? extends T>... classes) {
PsiElement run = element;
while (run != null) {
if (instanceOf(run, classes)) return (T)run;
if (instanceOf(run, classes)) {
//noinspection unchecked
return (T)run;
}
if (run instanceof PsiFile) break;
run = run.getParent();
}
@@ -546,6 +552,7 @@ public class PsiTreeUtil {
public static boolean processElements(@Nullable PsiElement element, @NotNull PsiElementProcessor processor) {
if (element == null) return true;
//noinspection unchecked
if (!processor.execute(element)) return false;
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
if (!processElements(child, processor)) return false;
@@ -832,11 +839,13 @@ public class PsiTreeUtil {
TextRange injectionRange = outerLanguageElement.getTextRange();
List<PsiElement> res = Lists.newArrayList();
assert psi != null : outerLanguageElement;
for (PsiElement element = psi.findElementAt(injectionRange.getStartOffset());
element != null && injectionRange.intersectsStrict(element.getTextRange());
element = element.getNextSibling()) {
res.add(element);
}
return res;
}
}
@@ -85,7 +85,7 @@ public class CodeInsightUtilBase {
T elementInRange = findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(),
(Class<? extends T>)element.getClass(),
language);
((RangeMarkerEx)rangeMarker).dispose();
rangeMarker.dispose();
return elementInRange;
}
@@ -19,10 +19,8 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.template.Template;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.paths.PsiDynaReference;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.TextRange;
import com.intellij.patterns.ElementPattern;
@@ -104,21 +102,17 @@ public class CompletionData {
public void completeReference(final PsiReference reference, final Set<LookupElement> set, @NotNull final PsiElement position, final PsiFile file,
final int offset){
final CompletionVariant[] variants = findVariants(position, file);
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
boolean hasApplicableVariants = false;
for (CompletionVariant variant : variants) {
if (variant.hasReferenceFilter()) {
variant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
hasApplicableVariants = true;
}
}
if (!hasApplicableVariants) {
myGenericVariant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
}
boolean hasApplicableVariants = false;
for (CompletionVariant variant : variants) {
if (variant.hasReferenceFilter()) {
variant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
hasApplicableVariants = true;
}
});
}
if (!hasApplicableVariants) {
myGenericVariant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
}
}
public void addKeywordVariants(Set<CompletionVariant> set, PsiElement position, final PsiFile file) {
@@ -129,11 +123,7 @@ public class CompletionData {
final PrefixMatcher matcher,
final PsiFile file){
for (final CompletionVariant variant : variants) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
variant.addKeywords(set, position, matcher, file, CompletionData.this);
}
});
variant.addKeywords(set, position, matcher, file, CompletionData.this);
}
}
@@ -142,34 +132,30 @@ public class CompletionData {
}
public CompletionVariant[] findVariants(final PsiElement position, final PsiFile file){
return ApplicationManager.getApplication().runReadAction(new Computable<CompletionVariant[]>() {
public CompletionVariant[] compute() {
final List<CompletionVariant> variants = new ArrayList<CompletionVariant>();
PsiElement scope = position;
if(scope == null){
scope = file;
}
while (scope != null) {
boolean breakFlag = false;
if (isScopeAcceptable(scope)){
final List<CompletionVariant> variants = new ArrayList<CompletionVariant>();
PsiElement scope = position;
if(scope == null){
scope = file;
}
while (scope != null) {
boolean breakFlag = false;
if (isScopeAcceptable(scope)){
for (final CompletionVariant variant : myCompletionVariants) {
if (variant.isVariantApplicable(position, scope) && !variants.contains(variant)) {
variants.add(variant);
if (variant.isScopeFinal(scope)) {
breakFlag = true;
}
for (final CompletionVariant variant : myCompletionVariants) {
if (variant.isVariantApplicable(position, scope) && !variants.contains(variant)) {
variants.add(variant);
if (variant.isScopeFinal(scope)) {
breakFlag = true;
}
}
}
if(breakFlag || isScopeFinal(scope.getClass()))
break;
scope = scope.getContext();
if (scope instanceof PsiDirectory) break;
}
return variants.toArray(new CompletionVariant[variants.size()]);
if(breakFlag || isScopeFinal(scope.getClass()))
break;
scope = scope.getContext();
if (scope instanceof PsiDirectory) break;
}
});
return variants.toArray(new CompletionVariant[variants.size()]);
}
protected final CompletionVariant myGenericVariant = new CompletionVariant() {
@@ -207,14 +193,7 @@ public class CompletionData {
public static String findPrefixStatic(final PsiElement insertedElement, final int offsetInFile, ElementPattern<Character> prefixStartTrim) {
if(insertedElement == null) return "";
final String prefix = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
public String compute() {
if (!insertedElement.isValid()) {
return "";
}
return getReferencePrefix(insertedElement, offsetInFile);
}
});
final String prefix = getReferencePrefix(insertedElement, offsetInFile);
if (prefix != null) return prefix;
if (insertedElement instanceof PsiPlainText || insertedElement instanceof PsiComment) {
@@ -88,7 +88,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
};
private LightweightHint myHint;
private final Semaphore myFreezeSemaphore;
private boolean myToRestart;
private Boolean myToRestart;
private boolean myModifiersReleased;
@@ -436,6 +436,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
private void finishCompletionProcess() {
myToRestart = false;
cancel();
assert !myDisposed;
@@ -474,7 +475,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
invokeLaterIfNotDispatch(new Runnable() {
public void run() {
if (isOutdated()) return;
if (isCanceled() && !myToRestart) return; // otherwise
if (isCanceled() && myToRestart != Boolean.TRUE) return;
//what if a new completion was invoked by the user before this 'later'?
if (CompletionProgressIndicator.this != CompletionServiceImpl.getCompletionService().getCurrentCompletion()) return;
@@ -528,6 +529,11 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
public void cancelByWriteAction() {
if (myToRestart != null) {
LOG.assertTrue(myToRestart == Boolean.FALSE); //explicit completionFinished was invoked before this write action
return;
}
myToRestart = true;
cancel();
@@ -605,7 +611,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
public void prefixUpdated() {
if (myToRestart) {
if (myToRestart == Boolean.TRUE) {
scheduleRestart();
return;
}
@@ -26,7 +26,6 @@ import com.intellij.psi.PsiReference;
import com.intellij.psi.filters.ContextGetter;
import com.intellij.psi.filters.ElementFilter;
import com.intellij.psi.filters.position.PatternFilter;
import com.intellij.util.PairConsumer;
import com.intellij.util.ReflectionCache;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
@@ -192,14 +191,6 @@ public class CompletionVariant {
}
}
public void processReferenceCompletions(PairConsumer<ElementFilter, TailType> consumer) {
for (final CompletionVariantItem ce : myCompletionsList) {
if(ce.myCompletion instanceof ElementFilter){
consumer.consume((ElementFilter)ce.myCompletion, ce.myTailType);
}
}
}
public void addKeywords(Set<LookupElement> set, PsiElement position, final PrefixMatcher matcher, final PsiFile file,
final CompletionData completionData){
@@ -17,15 +17,12 @@ package com.intellij.codeInsight.completion.impl;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -56,21 +53,11 @@ public class CompletionServiceImpl extends CompletionService{
}
public CompletionResultSet createResultSet(final CompletionParameters parameters, final Consumer<LookupElement> consumer,
@NotNull final CompletionContributor contributor) {
return ApplicationManager.getApplication().runReadAction(new Computable<CompletionResultSet>() {
public CompletionResultSet compute() {
final PsiElement position = parameters.getPosition();
if (!position.isValid()) {
throw new ProcessCanceledException();
}
final String prefix = CompletionData.findPrefixStatic(position, parameters.getOffset());
final String textBeforePosition = parameters.getPosition().getContainingFile().getText().substring(0, parameters.getOffset());
return new CompletionResultSetImpl(consumer, textBeforePosition, new CamelHumpMatcher(prefix), contributor);
}
});
@NotNull final CompletionContributor contributor) {
final PsiElement position = parameters.getPosition();
final String prefix = CompletionData.findPrefixStatic(position, parameters.getOffset());
final String textBeforePosition = parameters.getPosition().getContainingFile().getText().substring(0, parameters.getOffset());
return new CompletionResultSetImpl(consumer, textBeforePosition, new CamelHumpMatcher(prefix), contributor);
}
@Override
@@ -171,7 +171,7 @@ public class FileStatusMap implements Disposable {
else if (status.dirtyScopes.containsKey(passId)) {
RangeMarker marker = status.dirtyScopes.get(passId);
if (marker != null) {
((RangeMarkerEx)marker).dispose();
marker.dispose();
status.dirtyScopes.put(passId, null);
}
}
@@ -217,7 +217,7 @@ public class FileStatusMap implements Disposable {
LOG.assertTrue(status.dirtyScopes.containsKey(passId));
RangeMarker marker = status.dirtyScopes.get(passId);
if (marker != null) {
((RangeMarkerEx)marker).dispose();
marker.dispose();
}
marker = document.createRangeMarker(0, document.getTextLength());
status.dirtyScopes.put(passId, marker);
@@ -269,7 +269,7 @@ public class FileStatusMap implements Disposable {
if (union.getEndOffset() > textLength) {
union = union.intersection(new TextRange(0, textLength));
}
((RangeMarkerEx)old).dispose();
old.dispose();
return document.createRangeMarker(union);
}
@@ -266,7 +266,13 @@ public class TypedHandler implements TypedActionHandler {
for (DocumentWindow documentWindow : InjectedLanguageUtil.getCachedInjectedDocuments(oldFile)) {
if (documentWindow.isValid() && documentWindow.containsRange(offset, offset)) {
PsiFile injectedFile = PsiDocumentManager.getInstance(oldFile.getProject()).getPsiFile(documentWindow);
return InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
final Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
// IDEA-52375 fix: last quote sign should be handled by outer language quote handler
if (injectedEditor.getCaretModel().getOffset() == injectedEditor.getDocument().getTextLength() &&
charTyped == editor.getDocument().getCharsSequence().charAt(offset)) {
return editor;
}
return injectedEditor;
}
}
@@ -48,7 +48,7 @@ public abstract class TailTypeDecorator<T extends LookupElement> extends LookupE
final LookupItem lookupItem = delegate.as(LookupItem.class);
if (lookupItem != null && tailType != null) {
lookupItem.setTailType(TailType.NONE);
lookupItem.setTailType(TailType.UNKNOWN);
}
delegate.handleInsert(context);
if (tailType != null && tailType.isApplicable(context)) {
@@ -77,7 +77,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
private int myMinPrefixLength;
private int myPreferredItemsCount;
private long myShownStamp = -1;
private String myInitialPrefix;
private LookupArranger myArranger;
@@ -493,10 +492,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
}
public void finishLookup(final char completionChar) {
if (justShown()) {
return;
}
final LookupElement item = (LookupElement)myList.getSelectedValue();
doHide(false, true);
if (item == null ||
@@ -537,10 +532,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
fireItemSelected(item, completionChar);
}
public boolean justShown() {
return myShownStamp > 0 && System.currentTimeMillis() - myShownStamp < 42 && !ApplicationManager.getApplication().isUnitTestMode();
}
public int getLookupStart() {
if (myLookupStartMarker == null) {
final int start = calcLookupStart();
@@ -581,8 +572,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
hintManager.showEditorHint(this, myEditor, p, HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.UPDATE_BY_SCROLLING, 0, false);
getComponent().getRootPane().getLayeredPane().add(myIconPanel, 42, 0);
myShownStamp = System.currentTimeMillis();
}
private void addListeners() {
@@ -17,6 +17,8 @@
package com.intellij.codeInsight.lookup.impl;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.CompletionProcess;
import com.intellij.codeInsight.completion.CompletionService;
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
@@ -119,7 +121,10 @@ public class LookupManagerImpl extends LookupManager {
final Runnable request = new Runnable() {
public void run() {
if (myActiveLookup == lookup) {
DocumentationManager.getInstance(myProject).showJavaDocInfo(editor, psiFile, false);
final CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion();
if (completion == null || !completion.isAutopopupCompletion()) {
DocumentationManager.getInstance(myProject).showJavaDocInfo(editor, psiFile, false);
}
}
}
};
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.lookup.impl.actions;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.editor.Editor;
@@ -33,6 +34,7 @@ public class ChooseItemAction extends EditorAction {
private static class Handler extends EditorActionHandler {
public void execute(final Editor editor, final DataContext dataContext) {
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
assert lookup != null;
lookup.finishLookup(Lookup.NORMAL_SELECT_CHAR);
}
}
@@ -41,7 +43,8 @@ public class ChooseItemAction extends EditorAction {
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
if (lookup != null) {
lookup.refreshUi(); // to bring the list model up to date
presentation.setEnabled(!lookup.justShown() && (lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty()));
presentation.setEnabled(lookup.isFocused() &&
!ChooseItemReplaceAction.hasTemplatePrefix(lookup, TemplateSettings.ENTER_CHAR));
} else {
presentation.setEnabled(false);
}
@@ -17,15 +17,21 @@
package com.intellij.codeInsight.lookup.impl.actions;
import com.intellij.codeInsight.completion.CodeCompletionFeatures;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
public class ChooseItemReplaceAction extends EditorAction {
public ChooseItemReplaceAction(){
@@ -36,15 +42,28 @@ public class ChooseItemReplaceAction extends EditorAction {
public void executeWriteAction(Editor editor, DataContext dataContext) {
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_REPLACE);
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
assert lookup != null;
lookup.finishLookup(Lookup.REPLACE_SELECT_CHAR);
}
}
static boolean hasTemplatePrefix(LookupImpl lookup, char shortcutChar) {
final PsiFile file = lookup.getPsiFile();
final Editor editor = lookup.getEditor();
PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument());
final int offset = editor.getCaretModel().getOffset();
final String prefix = CompletionUtil.findJavaIdentifierPrefix(file, offset);
final TemplateImpl template = LiveTemplateCompletionContributor.findApplicableTemplate(file, offset, prefix);
return template != null && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template);
}
public void update(Editor editor, Presentation presentation, DataContext dataContext){
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
if (lookup != null) {
lookup.refreshUi(); // to bring the list model up to date
presentation.setEnabled(!lookup.justShown() && (lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty()));
presentation.setEnabled((lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty()) &&
!hasTemplatePrefix(lookup, TemplateSettings.TAB_CHAR));
} else {
presentation.setEnabled(false);
}
@@ -19,10 +19,17 @@ import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.util.Condition;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author peter
@@ -39,23 +46,42 @@ public class LiveTemplateCompletionContributor extends CompletionContributor {
final PsiFile file = parameters.getOriginalFile();
final int offset = parameters.getOffset();
final String prefix = result.getPrefixMatcher().getPrefix();
for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
final String key = template.getKey();
if (!template.isDeactivated() && !template.isSelectionTemplate() && TemplateManagerImpl.isApplicable(file, offset, template)) {
if (prefix.equals(key)) {
result.addElement(LookupElementBuilder.create(key).setTypeText(template.getDescription()).setInsertHandler(new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
context.setAddCompletionChar(false);
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template);
}
}));
} else {
result.restartCompletionOnPrefixChange(key);
final TemplateImpl template = findApplicableTemplate(file, offset, prefix);
if (template != null) {
result.addElement(LookupElementBuilder.create(prefix).setTypeText(template.getDescription()).setInsertHandler(new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
context.setAddCompletionChar(false);
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template);
}
}));
} else {
for (final TemplateImpl possible : listApplicableTemplates(file, offset)) {
result.restartCompletionOnPrefixChange(possible.getKey());
}
}
}
});
}
private static List<TemplateImpl> listApplicableTemplates(PsiFile file, int offset) {
final ArrayList<TemplateImpl> result = CollectionFactory.arrayList();
for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
if (!template.isDeactivated() && !template.isSelectionTemplate() && TemplateManagerImpl.isApplicable(file, offset, template)) {
result.add(template);
}
}
return result;
}
@Nullable
public static TemplateImpl findApplicableTemplate(PsiFile file, int offset, final String key) {
return ContainerUtil.find(listApplicableTemplates(file, offset), new Condition<TemplateImpl>() {
@Override
public boolean value(TemplateImpl template) {
return key.equals(template.getKey());
}
});
}
@@ -73,7 +73,7 @@ public class TemplateSegments {
public void replaceSegmentAt(int index, int start, int end) {
RangeMarker rangeMarker = mySegments.get(index);
((RangeMarkerEx)rangeMarker).dispose();
rangeMarker.dispose();
Document doc = myEditor.getDocument();
rangeMarker = doc.createRangeMarker(start, end);
rangeMarker.setGreedyToLeft(true);
@@ -690,7 +690,7 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
return candidates;
}
private char getShortcutChar(TemplateImpl template) {
public char getShortcutChar(TemplateImpl template) {
char c = template.getShortcutChar();
if (c == DEFAULT_CHAR) {
return getDefaultShortcutChar();
@@ -73,6 +73,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
private List<Element> myUnloadedElements = null;
private JDOMExternalizableStringList myOrder = new JDOMExternalizableStringList();
private boolean myOrdered = true;
private final EventDispatcher<RunManagerListener> myDispatcher = EventDispatcher.create(RunManagerListener.class);
@@ -286,7 +287,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
@Override
public Collection<RunnerAndConfigurationSettings> getSortedConfigurations() {
if (myOrder != null && !myOrder.isEmpty()) { //compatibility
if (!myOrdered && !myOrder.isEmpty()) { //compatibility
final HashMap<String, RunnerAndConfigurationSettings> settings =
new HashMap<String, RunnerAndConfigurationSettings>(myConfigurations); //sort shared and local configurations
myConfigurations.clear();
@@ -299,7 +300,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
for (String configName : order) {
myConfigurations.put(configName, settings.get(configName));
}
myOrder = null;
myOrdered = true;
}
return myConfigurations.values();
}
@@ -474,9 +475,8 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
}
}
if (myOrder != null) {
myOrder.readExternal(parentNode);
}
myOrder.readExternal(parentNode);
myOrdered = false;
mySelectedConfig = parentNode.getAttributeValue(SELECTED_ATTR);
fireBeforeRunTasksUpdated();
@@ -799,7 +799,6 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
}
public void shareConfiguration(final RunConfiguration runConfiguration, final boolean shareConfiguration) {
if (shareConfiguration && isTemporary(runConfiguration)) makeStable(runConfiguration);
mySharedConfigurations.put(runConfiguration.getUniqueID(), shareConfiguration);
}
@@ -222,6 +222,7 @@ public class FileTemplateUtil{
Velocity.setProperty("class.resource.loader.class", MyClasspathResourceLoader.class.getName());
Velocity.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, modifiedPatternsPath.getAbsolutePath());
Velocity.setProperty(RuntimeConstants.INPUT_ENCODING, FileTemplate.ourEncoding);
Velocity.setProperty(RuntimeConstants.PARSER_POOL_SIZE, 3);
Velocity.init();
ourVelocityInitialized = true;
}
@@ -0,0 +1,45 @@
/*
* 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.projectView.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
/**
* @author yole
*/
public class MarkExcludeRootAction extends MarkRootAction {
public MarkExcludeRootAction() {
super(false, true);
}
@Override
public void actionPerformed(AnActionEvent e) {
VirtualFile[] vFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
String message = vFiles.length == 1 ? FileUtil.toSystemDependentName(vFiles [0].getPath()) : vFiles.length + " selected files";
final int rc = Messages.showOkCancelDialog(e.getData(PlatformDataKeys.PROJECT),
"Are you sure you would you like to exclude " + message +
" from the project?\nYou can restore excluded folders later using the Project Structure dialog.",
"Mark as Excluded", Messages.getQuestionIcon());
if (rc != 0) {
return;
}
super.actionPerformed(e);
}
}
@@ -0,0 +1,122 @@
/*
* 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.projectView.actions;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class MarkRootAction extends AnAction {
private final boolean myMarkAsTestSources;
private final boolean myMarkAsExcluded;
public MarkRootAction() {
myMarkAsTestSources = false;
myMarkAsExcluded = false;
}
protected MarkRootAction(boolean markAsTestSources, boolean markAsExcluded) {
myMarkAsTestSources = markAsTestSources;
myMarkAsExcluded = markAsExcluded;
}
@Override
public void actionPerformed(AnActionEvent e) {
Module module = e.getData(LangDataKeys.MODULE);
VirtualFile[] vFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
assert vFiles != null;
final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
for (VirtualFile vFile : vFiles) {
ContentEntry entry = findContentEntry(model, vFile);
if (entry != null) {
final SourceFolder[] sourceFolders = entry.getSourceFolders();
for (SourceFolder sourceFolder : sourceFolders) {
if (sourceFolder.getFile() == vFile) {
entry.removeSourceFolder(sourceFolder);
break;
}
}
if (myMarkAsExcluded) {
entry.addExcludeFolder(vFile);
}
else {
entry.addSourceFolder(vFile, myMarkAsTestSources);
}
}
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
model.commit();
}
});
}
@Nullable
private static ContentEntry findContentEntry(ModifiableRootModel model, VirtualFile vFile) {
final ContentEntry[] contentEntries = model.getContentEntries();
for (ContentEntry contentEntry : contentEntries) {
final VirtualFile contentEntryFile = contentEntry.getFile();
if (contentEntryFile != null && VfsUtil.isAncestor(contentEntryFile, vFile, false)) {
return contentEntry;
}
}
return null;
}
@Override
public void update(AnActionEvent e) {
boolean enabled = canMark(e, myMarkAsTestSources || myMarkAsExcluded, !myMarkAsTestSources || myMarkAsExcluded);
e.getPresentation().setVisible(enabled);
e.getPresentation().setEnabled(enabled);
}
public static boolean canMark(AnActionEvent e, boolean acceptSourceRoot, boolean acceptTestSourceRoot) {
Module module = e.getData(LangDataKeys.MODULE);
VirtualFile[] vFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
if (module == null || vFiles == null) {
return false;
}
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(module.getProject()).getFileIndex();
for (VirtualFile vFile : vFiles) {
if (!vFile.isDirectory()) {
return false;
}
if (!fileIndex.isInContent(vFile)) {
return false;
}
if (fileIndex.getSourceRootForFile(vFile) == vFile) {
boolean isTestSourceRoot = fileIndex.isInTestSourceContent(vFile);
if (acceptSourceRoot && !isTestSourceRoot) return true;
if (acceptTestSourceRoot && isTestSourceRoot) return true;
}
if (fileIndex.isInSourceContent(vFile)) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,29 @@
/*
* 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.projectView.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
/**
* @author yole
*/
public class MarkRootGroup extends DefaultActionGroup {
@Override
public void update(AnActionEvent e) {
e.getPresentation().setVisible(MarkRootAction.canMark(e, true, true));
}
}
@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.util.gotoByName.matchers;
package com.intellij.ide.projectView.actions;
import com.intellij.openapi.util.Computable;
import java.util.Set;
public interface EntityMatcher {
boolean nameMatches(String shortPattern, String shortName);
Set<Object> getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable<Boolean> isCancelled);
/**
* @author yole
*/
public class MarkTestSourceRootAction extends MarkRootAction {
public MarkTestSourceRootAction() {
super(true, false);
}
}
@@ -1497,6 +1497,10 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat
return getPaneOptionValue(myShowMembers, paneId, ourShowMembersDefaults);
}
public void setShowMembers(boolean showMembers, String paneId) {
setPaneOption(myShowMembers, showMembers, paneId, true);
}
public boolean isHideEmptyMiddlePackages(String paneId) {
return getPaneOptionValue(myHideEmptyPackages, paneId, ourHideEmptyPackagesDefaults);
}
@@ -39,7 +39,7 @@ public abstract class LangScriptingContextConfigurable implements Configurable,
public LangScriptingContextConfigurable(Project project, LangScriptingContextProvider provider) {
myLibManager = new ScriptingLibraryManager(project, provider.getLibraryType());
myPanel = useDedicatedLibraryUI() ? new ScriptingLibrariesPanel(provider, project, myLibManager) : new ScriptingLibrariesPanelStub();
myContextsConfigurable = new ScriptingContextsConfigurable(project, provider);
myContextsConfigurable = new ScriptingContextsConfigurable(project, provider.getLibraryMappings(project));
}
private boolean useDedicatedLibraryUI() {
@@ -70,6 +70,7 @@ public abstract class LangScriptingContextConfigurable implements Configurable,
public void run() {
myLibManager.commitChanges();
myPanel.resetTable();
myContextsConfigurable.resetMappings();
}
});
}
@@ -17,9 +17,11 @@ package com.intellij.ide.scriptingContext;
import com.intellij.lang.Language;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.LibraryType;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Rustam Vishnyakov
@@ -37,4 +39,7 @@ public abstract class LangScriptingContextProvider {
public abstract boolean isCompact(VirtualFile file);
@Nullable
public abstract String getLibraryTypeName(OrderRootType rootType);
}
@@ -47,6 +47,10 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
return library.getName();
}
public void reset() {
myLibraryManager.reset();
}
@NotNull
@Override
protected String getValueAttribute() {
@@ -75,7 +79,6 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
@Override
public Collection<ScriptingLibraryTable.LibraryModel> getAvailableValues(VirtualFile file) {
myLibraryManager.reset();
List<ScriptingLibraryTable.LibraryModel> libraries = getSingleLibraries();
if (myCompoundLibMap.containsKey(file)) {
libraries.add(myCompoundLibMap.get(file));
@@ -127,7 +130,7 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
}
public static class CompoundLibrary extends ScriptingLibraryTable.LibraryModel {
private List<ScriptingLibraryTable.LibraryModel> myLibraries = new ArrayList<ScriptingLibraryTable.LibraryModel>();
private final Map<String, ScriptingLibraryTable.LibraryModel> myLibraries = new TreeMap<String, ScriptingLibraryTable.LibraryModel>();
public CompoundLibrary() {
super(null);
@@ -138,20 +141,19 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
}
public void toggleLibrary(@NotNull ScriptingLibraryTable.LibraryModel library) {
for (ScriptingLibraryTable.LibraryModel lib : myLibraries) {
if (lib == library) {
myLibraries.remove(library);
return;
}
String libName = library.getName();
if (myLibraries.containsKey(libName)) {
myLibraries.remove(libName);
return;
}
myLibraries.add(library);
myLibraries.put(libName, library);
}
@Override
public String getName() {
StringBuffer allNames = new StringBuffer();
boolean isFirst = true;
for (ScriptingLibraryTable.LibraryModel library : myLibraries) {
for (ScriptingLibraryTable.LibraryModel library : myLibraries.values()) {
allNames.append(isFirst ? "" : ", ");
allNames.append(library.getName());
isFirst = false;
@@ -161,7 +163,7 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
@Override
public boolean containsFile(VirtualFile file) {
for (ScriptingLibraryTable.LibraryModel library : myLibraries) {
for (ScriptingLibraryTable.LibraryModel library : myLibraries.values()) {
if (library.containsFile(file)) return true;
}
return false;
@@ -19,6 +19,7 @@ import com.intellij.ide.scriptingContext.LangScriptingContextProvider;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.scripting.ScriptingLibraryTable;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
@@ -42,8 +43,8 @@ public class EditLibraryDialog extends DialogWrapper {
private static final int FILE_LOCATION_COL = 0;
private static final int FILE_TYPE_COL = 1;
private static final String SOURCE_TYPE = "Source";
private static final String COMPACT_TYPE = "Compact";
private final String mySourceTypeName;
private final String myCompactTypeName;
private JPanel contentPane;
private JTextField myLibName;
@@ -60,6 +61,8 @@ public class EditLibraryDialog extends DialogWrapper {
super(true);
setTitle(title);
myProvider = provider;
mySourceTypeName = provider.getLibraryTypeName(OrderRootType.SOURCES);
myCompactTypeName = provider.getLibraryTypeName(OrderRootType.CLASSES);
myAddFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -95,7 +98,7 @@ public class EditLibraryDialog extends DialogWrapper {
TableColumn typeCol = myFileTable.getColumnModel().getColumn(FILE_TYPE_COL);
typeCol.setMaxWidth(80);
MyTableCellEditor cellEditor = new MyTableCellEditor(new JComboBox(new String[] {SOURCE_TYPE, COMPACT_TYPE}), myFileTableModel);
MyTableCellEditor cellEditor = new MyTableCellEditor(new JComboBox(new String[] {mySourceTypeName, myCompactTypeName}), myFileTableModel);
typeCol.setCellEditor(cellEditor);
}
@@ -105,7 +108,7 @@ public class EditLibraryDialog extends DialogWrapper {
myFileTableModel.setFiles(lib.getSourceFiles(), lib.getCompactFiles());
}
private static class MyTableCellEditor extends DefaultCellEditor {
private class MyTableCellEditor extends DefaultCellEditor {
private FileTableModel myFileTableModel;
private VirtualFile myFile;
@@ -119,7 +122,7 @@ public class EditLibraryDialog extends DialogWrapper {
public boolean stopCellEditing() {
if (myFile != null) {
Object value = getCellEditorValue();
myFileTableModel.setFileType(myFile, value.equals(COMPACT_TYPE));
myFileTableModel.setFileType(myFile, value.equals(myCompactTypeName));
}
return super.stopCellEditing();
}
@@ -254,7 +257,7 @@ public class EditLibraryDialog extends DialogWrapper {
case FILE_LOCATION_COL:
return file;
case FILE_TYPE_COL:
return myCompactFiles.contains(file) ? COMPACT_TYPE : SOURCE_TYPE;
return myCompactFiles.contains(file) ? myCompactTypeName : mySourceTypeName;
}
return "";
}
@@ -15,7 +15,7 @@
*/
package com.intellij.ide.scriptingContext.ui;
import com.intellij.ide.scriptingContext.LangScriptingContextProvider;
import com.intellij.ide.scriptingContext.ScriptingLibraryMappings;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.libraries.scripting.ScriptingLibraryTable;
import com.intellij.openapi.util.IconLoader;
@@ -30,10 +30,23 @@ import javax.swing.*;
*/
public class ScriptingContextsConfigurable extends LanguagePerFileConfigurable<ScriptingLibraryTable.LibraryModel> {
public ScriptingContextsConfigurable(final Project project, final LangScriptingContextProvider provider) {
super(project, ScriptingLibraryTable.LibraryModel.class, provider.getLibraryMappings(project),
private final ScriptingLibraryMappings myScriptingLibraryMappings;
public ScriptingContextsConfigurable(final Project project, final ScriptingLibraryMappings mappings) {
super(project, ScriptingLibraryTable.LibraryModel.class, mappings,
"Specify which libraries are used in specific files and/or directories.", "Library",
"Override library settings for child directories and files?", "Override Library Settings");
myScriptingLibraryMappings = mappings;
}
public void resetMappings() {
myScriptingLibraryMappings.reset();
}
@Override
public void reset() {
resetMappings();
super.reset();
}
@Override
@@ -20,12 +20,11 @@ import com.intellij.Patches;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.actions.CopyReferenceAction;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.util.gotoByName.matchers.DefaultMatcher;
import com.intellij.ide.util.gotoByName.matchers.EntityMatcher;
import com.intellij.openapi.MnemonicHelper;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.keymap.KeymapManager;
@@ -33,15 +32,19 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.statistics.StatisticsInfo;
import com.intellij.psi.statistics.StatisticsManager;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.ListScrollingUtil;
import com.intellij.ui.ScrollPaneFactory;
@@ -49,6 +52,9 @@ import com.intellij.ui.components.JBList;
import com.intellij.ui.popup.PopupOwner;
import com.intellij.ui.popup.PopupUpdateProcessor;
import com.intellij.util.Alarm;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.diff.Diff;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
@@ -62,14 +68,19 @@ import javax.swing.event.ListSelectionListener;
import javax.swing.text.DefaultEditorKit;
import java.awt.*;
import java.awt.event.*;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.List;
public abstract class ChooseByNameBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ChooseByNameBase");
protected final Project myProject;
protected final ChooseByNameModel myModel;
protected final String myInitialText;
private boolean myPreselectInitialText;
private final Reference<PsiElement> myContext;
protected Component myPreviouslyFocusedComponent;
@@ -104,14 +115,10 @@ public abstract class ChooseByNameBase {
private static int VISIBLE_LIST_SIZE_LIMIT = 10;
private static final int MAXIMUM_LIST_SIZE_LIMIT = 30;
private int myMaximumListSizeLimit = MAXIMUM_LIST_SIZE_LIMIT;
@NonNls
private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib";
@NonNls
private static final String NOT_FOUND_CARD = "nfound";
@NonNls
private static final String CHECK_BOX_CARD = "chkbox";
@NonNls
private static final String SEARCHING_CARD = "searching";
@NonNls private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib";
@NonNls private static final String NOT_FOUND_CARD = "nfound";
@NonNls private static final String CHECK_BOX_CARD = "chkbox";
@NonNls private static final String SEARCHING_CARD = "searching";
private static final int REBUILD_DELAY = 300;
private final Alarm myHideAlarm = new Alarm();
@@ -119,26 +126,32 @@ public abstract class ChooseByNameBase {
protected JBPopup myTextPopup;
protected JBPopup myDropdownPopup;
private EntityMatcher myMatcher;
private static class MatchesComparator implements Comparator<String> {
private final String myOriginalPattern;
private MatchesComparator(final String originalPattern) {
myOriginalPattern = originalPattern.trim();
}
public int compare(final String a, final String b) {
boolean aStarts = a.startsWith(myOriginalPattern);
boolean bStarts = b.startsWith(myOriginalPattern);
if (aStarts && bStarts) return a.compareToIgnoreCase(b);
if (aStarts && !bStarts) return -1;
if (bStarts && !aStarts) return 1;
return a.compareToIgnoreCase(b);
}
}
/**
* @param initialText initial text which will be in the lookup text field
* @param context
*/
protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, final PsiElement context) {
this(project, model, initialText);
myMatcher = new DefaultMatcher(model, context);
}
protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, EntityMatcher matcher) {
this(project, model, initialText);
myMatcher = matcher;
}
private ChooseByNameBase(Project project, ChooseByNameModel model, String initialText) {
myProject = project;
myModel = model;
myInitialText = initialText;
myContext = new WeakReference<PsiElement>(context);
}
public boolean isPreselectInitialText() {
@@ -259,7 +272,7 @@ public abstract class ChooseByNameBase {
/**
* @param callback
* @param modalityState - if not null rebuilds list in given {@link com.intellij.openapi.application.ModalityState}
* @param modalityState - if not null rebuilds list in given {@link ModalityState}
* @param allowMultipleSelection
*/
protected void initUI(final ChooseByNamePopupComponent.Callback callback,
@@ -284,8 +297,7 @@ public abstract class ChooseByNameBase {
GridBagLayout gb = new GridBagLayout();
JPanel eastWrapper = new JPanel(gb);
gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
eastWrapper.add(hBox);
caption2Tools.add(eastWrapper, BorderLayout.CENTER);
@@ -435,7 +447,8 @@ public abstract class ChooseByNameBase {
myListModel = new DefaultListModel();
myList = new JBList(myListModel);
myList.setFocusable(false);
myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION);
myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION :
ListSelectionModel.SINGLE_SELECTION);
myList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (!myTextField.hasFocus()) {
@@ -577,8 +590,8 @@ public abstract class ChooseByNameBase {
final int paneHeight = layeredPane.getHeight();
final int y = paneHeight / 3 - preferredTextFieldPanelSize.height / 2;
VISIBLE_LIST_SIZE_LIMIT =
Math.max(10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1);
VISIBLE_LIST_SIZE_LIMIT = Math.max
(10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1);
ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(myTextFieldPanel, myTextField);
builder.setCancelCallback(new Computable<Boolean>() {
@@ -614,11 +627,9 @@ public abstract class ChooseByNameBase {
layeredPane = ((JDialog)parent).getLayeredPane();
}
else {
throw new IllegalStateException("cannot find parent window: project=" +
myProject +
throw new IllegalStateException("cannot find parent window: project=" + myProject +
(myProject != null ? "; open=" + myProject.isOpen() : "") +
"; window=" +
window);
"; window=" + window);
}
return layeredPane;
}
@@ -639,7 +650,8 @@ public abstract class ChooseByNameBase {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
final String text = myTextField.getText();
if (!canShowListForEmptyPattern() && (text == null || text.trim().length() == 0)) {
if (!canShowListForEmptyPattern() &&
(text == null || text.trim().length() == 0)) {
myListModel.clear();
hideList();
myCard.show(myCardContainer, CHECK_BOX_CARD);
@@ -779,12 +791,17 @@ public abstract class ChooseByNameBase {
return "choose_by_name#" + myModel.getPromptText() + "#" + myCheckBox.isSelected() + "#" + myTextField.getText();
}
public String getNamePattern(String pattern) {
return getNamePattern_static(myModel, pattern);
private String getQualifierPattern(String pattern) {
final String[] separators = myModel.getSeparators();
int lastSeparatorOccurence = 0;
for (String separator : separators) {
lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator));
}
return pattern.substring(0, lastSeparatorOccurence);
}
public static String getNamePattern_static(ChooseByNameModel model, String pattern) {
final String[] separators = model.getSeparators();
public String getNamePattern(String pattern) {
final String[] separators = myModel.getSeparators();
int lastSeparatorOccurence = 0;
for (String separator : separators) {
final int idx = pattern.lastIndexOf(separator);
@@ -970,7 +987,7 @@ public abstract class ChooseByNameBase {
protected void processKeyEvent(KeyEvent e) {
final KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
if (myCompletionKeyStroke != null && keyStroke.equals(myCompletionKeyStroke)) {
completionKeyStrokeHappened = true;
e.consume();
@@ -1021,7 +1038,8 @@ public abstract class ChooseByNameBase {
}
private void fillInCommonPrefix(final String pattern) {
final List<String> list = getNamesByPattern(pattern, getNames());
final ArrayList<String> list = new ArrayList<String>();
getNamesByPattern(myCheckBox.isSelected(), null, list, pattern);
if (isComplexPattern(pattern)) return; //TODO: support '*'
final String oldText = myTextField.getText();
@@ -1087,34 +1105,6 @@ public abstract class ChooseByNameBase {
}
}
public List<String> getNamesByPattern(String pattern, String[] names) {
if (pattern.startsWith("@")) {
pattern = pattern.substring(1);
}
boolean empty = pattern.length() == 0;
if (empty) {
if (!canShowListForEmptyPattern()) return Collections.emptyList();
return Arrays.asList(names);
}
ArrayList<String> result = new ArrayList<String>();
try {
for (String name : names) {
if (myCalcElementsThread.myCancelled) {
break;
}
if (myMatcher.nameMatches(pattern, name)) {
result.add(name);
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
}
return result;
}
private static final String EXTRA_ELEM = "...";
private class CalcElementsThread implements Runnable {
@@ -1203,31 +1193,55 @@ public abstract class ChooseByNameBase {
}
private void addElementsByPattern(Set<Object> elementsArray, String pattern) {
String[] names = myCheckboxState ? myNames[1] : myNames[0];
String namePattern = getNamePattern(pattern);
String qualifierPattern = getQualifierPattern(pattern);
List<String> namesList = getNamesByPattern(namePattern, names);
boolean empty = namePattern.length() == 0 || namePattern.equals("@"); // TODO[yole]: remove implicit dependency
if (empty && !canShowListForEmptyPattern()) return;
List<String> namesList = new ArrayList<String>();
getNamesByPattern(myCheckboxState, this, namesList, namePattern);
if (myCancelled) {
throw new ProcessCanceledException();
}
// Here we sort using namePattern to have similar logic with empty qualified patten case
Collections.sort(namesList, new MatchesComparator(namePattern));
boolean overflow = false;
List<Object> sameNameElements = new SmartList<Object>();
All:
for (String name : namesList) {
Set<Object> elems = myMatcher.getElementsByPattern(namePattern, name, myCheckboxState,new Computable<Boolean>() {
public Boolean compute() {
return myCancelled;
}
});
if (elementsArray.size() + elems.size() <= myMaximumListSizeLimit) {
elementsArray.addAll(elems);
if (myCancelled) {
throw new ProcessCanceledException();
}
else {
Iterator<Object> iter = elems.iterator();
while (elementsArray.size() < myMaximumListSizeLimit) {
elementsArray.add(iter.next());
final Object[] elements = myModel.getElementsByName(name, myCheckboxState, namePattern);
if (elements.length > 1) {
sameNameElements.clear();
for (final Object element : elements) {
if (matchesQualifier(element, qualifierPattern)) {
sameNameElements.add(element);
}
}
sortByProximity(sameNameElements);
for (Object element : sameNameElements) {
elementsArray.add(element);
if (elementsArray.size() >= myMaximumListSizeLimit) {
overflow = true;
break All;
}
}
elementsArray.add(EXTRA_ELEM);
break;
}
else if (elements.length == 1 && matchesQualifier(elements[0], qualifierPattern)) {
elementsArray.add(elements[0]);
if (elementsArray.size() >= myMaximumListSizeLimit) {
overflow = true;
break;
}
}
}
if (overflow) {
elementsArray.add(EXTRA_ELEM);
}
}
@@ -1238,8 +1252,92 @@ public abstract class ChooseByNameBase {
}
}
private String[] getNames() {
return myCheckBox.isSelected() ? myNames[1] : myNames[0];
private void sortByProximity(final List<Object> sameNameElements) {
Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get()));
}
private List<String> split(String s) {
List<String> answer = new ArrayList<String>();
for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) {
if (token.length() > 0) {
answer.add(token);
}
}
return answer.isEmpty() ? Collections.singletonList(s) : answer;
}
private boolean matchesQualifier(final Object element, final String qualifierPattern) {
final String name = myModel.getFullName(element);
if (name == null) return false;
final List<String> suspects = split(name);
final List<Pair<String, NameUtil.Matcher>> patternsAndMatchers =
ContainerUtil.map2List(split(qualifierPattern), new Function<String, Pair<String, NameUtil.Matcher>>() {
public Pair<String, NameUtil.Matcher> fun(String s) {
final String pattern = getNamePattern(s);
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
return new Pair<String, NameUtil.Matcher>(pattern, matcher);
}
});
int matchPosition = 0;
try {
patterns:
for (Pair<String, NameUtil.Matcher> patternAndMatcher : patternsAndMatchers) {
final String pattern = patternAndMatcher.first;
final NameUtil.Matcher matcher = patternAndMatcher.second;
if (pattern.length() > 0) {
for (int j = matchPosition; j < suspects.size() - 1; j++) {
String suspect = suspects.get(j);
if (matches(pattern, matcher, suspect)) {
matchPosition = j + 1;
continue patterns;
}
}
return false;
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
return false;
}
return true;
}
private void getNamesByPattern(final boolean checkboxState,
CalcElementsThread calcElementsThread,
final List<String> list,
String pattern) throws ProcessCanceledException {
if (!canShowListForEmptyPattern()) {
LOG.assertTrue(pattern.length() > 0);
}
if (pattern.startsWith("@")) {
pattern = pattern.substring(1);
}
final String[] names = checkboxState ? myNames[1] : myNames[0];
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
try {
for (String name : names) {
if (calcElementsThread != null && calcElementsThread.myCancelled) {
break;
}
if (matches(pattern, matcher, name)) {
list.add(name);
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
}
}
private boolean canShowListForEmptyPattern() {
@@ -1247,27 +1345,46 @@ public abstract class ChooseByNameBase {
}
protected boolean lastKeyStrokeIsCompletion() {
return myTextField.isCompletionKeyStroke();
return myTextField.isCompletionKeyStroke();
}
private boolean matches(String pattern, NameUtil.Matcher matcher, String name) {
boolean matches = false;
if (name != null) {
if (myModel instanceof CustomMatcherModel) {
if (((CustomMatcherModel)myModel).matches(name, pattern)) {
matches = true;
}
}
else if (pattern.length() == 0 || matcher.matches(name)) {
matches = true;
}
}
return matches;
}
private NameUtil.Matcher buildPatternMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
}
private interface CalcElementsCallback {
void run(Set<?> elements);
}
private static class MatchesComparator implements Comparator<String> {
private final String myOriginalPattern;
private static class PathProximityComparator implements Comparator<Object> {
private final ChooseByNameModel myModel;
private final PsiProximityComparator myProximityComparator;
private MatchesComparator(final String originalPattern) {
myOriginalPattern = originalPattern.trim();
private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) {
myModel = model;
myProximityComparator = new PsiProximityComparator(context);
}
public int compare(final String a, final String b) {
boolean aStarts = a.startsWith(myOriginalPattern);
boolean bStarts = b.startsWith(myOriginalPattern);
if (aStarts && bStarts) return a.compareToIgnoreCase(b);
if (aStarts && !bStarts) return -1;
if (bStarts && !aStarts) return 1;
return a.compareToIgnoreCase(b);
public int compare(final Object o1, final Object o2) {
int rc = myProximityComparator.compare(o1, o2);
if (rc != 0) return rc;
return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2));
}
}
@@ -17,7 +17,6 @@
package com.intellij.ide.util.gotoByName;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.util.gotoByName.matchers.EntityMatcher;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
@@ -43,7 +42,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent {
public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent{
private static final Key<ChooseByNamePopup> CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY = new Key<ChooseByNamePopup>("ChooseByNamePopup");
private Component myOldFocusOwner = null;
private boolean myShowListForEmptyPattern = false;
@@ -59,17 +58,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
}
}
private ChooseByNamePopup(final Project project, final ChooseByNameModel model, final ChooseByNamePopup oldPopup,
EntityMatcher matcher,@Nullable final String predefinedText) {
super(project, model, oldPopup != null ? oldPopup.getEnteredText() : predefinedText, matcher);
if (oldPopup == null && predefinedText != null) {
setPreselectInitialText(true);
}
if (oldPopup != null) { //inherit old focus owner
myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent;
}
}
public String getEnteredText() {
return myTextField.getText();
}
@@ -215,22 +203,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context) {
return createPopup(project, model, context, null);
}
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher) {
return createPopup(project, model, matcher, null);
}
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher,
@Nullable final String predefinedText) {
final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
if (oldPopup != null) {
oldPopup.close(false);
}
ChooseByNamePopup newPopup = new ChooseByNamePopup(project, model, oldPopup, matcher, predefinedText);
project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup);
return newPopup;
}
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context,
@Nullable final String predefinedText) {
final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
@@ -1,194 +0,0 @@
/*
* 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.util.gotoByName.matchers;
import com.intellij.ide.util.gotoByName.ChooseByNameBase;
import com.intellij.ide.util.gotoByName.ChooseByNameModel;
import com.intellij.ide.util.gotoByName.CustomMatcherModel;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import java.lang.ref.WeakReference;
import java.util.*;
public class DefaultMatcher implements EntityMatcher {
private ChooseByNameModel myModel;
private WeakReference<PsiElement> myContext;
private String myPattern = null;
private NameUtil.Matcher myMatcher = null;
public DefaultMatcher(ChooseByNameModel model, PsiElement context) {
myModel = model;
myContext = new WeakReference<PsiElement>(context);
}
public boolean nameMatches(String shortPattern, String shortName) {
if (myPattern == null || !myPattern.equals(shortPattern)) {
myMatcher = buildPatternMatcher(shortPattern);
myPattern = shortPattern;
}
return matches(shortPattern, myMatcher, shortName);
}
public Set<Object> getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable<Boolean> isCancelled) {
String namePattern = getShortNamePattern(fullPattern);
String qualifierPattern = getQualifierPattern(fullPattern);
//todo this is a code duplicate - remove it
String newPattern = namePattern.startsWith("@") ? namePattern.substring(1) : namePattern;
if (!nameMatches(newPattern, shortName)) return Collections.emptySet();
List<Object> sameNameElements = new SmartList<Object>();
final Object[] elements = myModel.getElementsByName(shortName, checkboxState, namePattern);
Set<Object> result = new HashSet<Object>();
if (elements.length == 1) {
if (matchesQualifier(elements[0], qualifierPattern)) {
result.add(elements[0]);
}
return result;
}
sameNameElements.clear();
for (final Object element : elements) {
if (isCancelled.compute()) return result;
if (matchesQualifier(element, qualifierPattern)) {
sameNameElements.add(element);
}
}
sortByProximity(sameNameElements);
result.addAll(sameNameElements);
return result;
}
private void sortByProximity(final List<Object> sameNameElements) {
Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get()));
}
private boolean matchesQualifier(final Object element, final String qualifierPattern) {
final String name = myModel.getFullName(element);
if (name == null) return false;
final List<String> suspects = split(name);
final List<Pair<String, NameUtil.Matcher>> patternsAndMatchers =
ContainerUtil.map2List(split(qualifierPattern), new Function<String, Pair<String, NameUtil.Matcher>>() {
public Pair<String, NameUtil.Matcher> fun(String s) {
final String pattern = getShortNamePattern(s);
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
return new Pair<String, NameUtil.Matcher>(pattern, matcher);
}
});
int matchPosition = 0;
try {
patterns:
for (Pair<String, NameUtil.Matcher> patternAndMatcher : patternsAndMatchers) {
final String pattern = patternAndMatcher.first;
final NameUtil.Matcher matcher = patternAndMatcher.second;
if (pattern.length() > 0) {
for (int j = matchPosition; j < suspects.size() - 1; j++) {
String suspect = suspects.get(j);
if (matches(pattern, matcher, suspect)) {
matchPosition = j + 1;
continue patterns;
}
}
return false;
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
return false;
}
return true;
}
public String getShortNamePattern(String s) {
return ChooseByNameBase.getNamePattern_static(myModel, s);
}
private String getQualifierPattern(String pattern) {
final String[] separators = myModel.getSeparators();
int lastSeparatorOccurence = 0;
for (String separator : separators) {
lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator));
}
return pattern.substring(0, lastSeparatorOccurence);
}
private boolean matches(String pattern, NameUtil.Matcher matcher, String name) {
boolean matches = false;
if (name != null) {
if (myModel instanceof CustomMatcherModel) {
if (((CustomMatcherModel)myModel).matches(name, pattern)) {
matches = true;
}
}
else if (pattern.length() == 0 || matcher.matches(name)) {
matches = true;
}
}
return matches;
}
private static NameUtil.Matcher buildPatternMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
}
private List<String> split(String s) {
List<String> answer = new ArrayList<String>();
for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) {
if (token.length() > 0) {
answer.add(token);
}
}
return answer.isEmpty() ? Collections.singletonList(s) : answer;
}
private static class PathProximityComparator implements Comparator<Object> {
private final ChooseByNameModel myModel;
private final PsiProximityComparator myProximityComparator;
private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) {
myModel = model;
myProximityComparator = new PsiProximityComparator(context);
}
public int compare(final Object o1, final Object o2) {
int rc = myProximityComparator.compare(o1, o2);
if (rc != 0) return rc;
return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2));
}
}
}
@@ -758,7 +758,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
public void dispose() {
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
RangeMarker rangeMarker = shred.getHostRangeMarker();
((RangeMarkerEx)rangeMarker).dispose();
rangeMarker.dispose();
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.internal.psiView;
import com.intellij.ide.ui.ListCellRendererWrapper;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageUtil;
@@ -357,13 +358,10 @@ public class PsiViewerDialog extends DialogWrapper implements DataProvider {
updateDialectsCombo();
updateExtentionsCombo();
myDialectsComboBox.setRenderer(new DefaultListCellRenderer() {
myDialectsComboBox.setRenderer(new ListCellRendererWrapper<Language>(myDialectsComboBox.getRenderer()) {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
final Component result = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value == null) setText("<no dialect>");
return result;
public void customize(final JList list, final Language value, final int index, final boolean selected, final boolean hasFocus) {
setText(value != null ? value.getDisplayName() : "<no dialect>");
}
});
File diff suppressed because it is too large Load Diff
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
import com.intellij.codeInspection.ModifiableModel;
import com.intellij.codeInspection.ex.InspectionProfileImpl;
import com.intellij.codeInspection.ex.InspectionToolRegistrar;
import com.intellij.ide.ui.ListCellRendererWrapper;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.colors.CodeInsightColors;
@@ -259,19 +260,13 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple
}
public JComponent createComponent() {
myProfiles.setRenderer(new DefaultListCellRenderer(){
myProfiles.setRenderer(new ListCellRendererWrapper<Profile>(myProfiles.getRenderer()) {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
final Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
final String profileName = ((Profile)value).getName();
public void customize(final JList list, final Profile value, final int index, final boolean selected, final boolean hasFocus) {
final String profileName = value.getName();
setText(profileName);
final SingleInspectionProfilePanel panel = myPanels.get(profileName);
if (panel != null && panel.isProfileShared()) {
setIcon(Profile.PROJECT_PROFILE);
} else {
setIcon(Profile.LOCAL_PROFILE);
}
return rendererComponent;
setIcon(panel != null && panel.isProfileShared() ? Profile.PROJECT_PROFILE : Profile.LOCAL_PROFILE);
}
});
myProfiles.addActionListener(new ActionListener() {
@@ -50,11 +50,9 @@ import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.impl.source.resolve.FileContextUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.FileContentUtil;
import com.intellij.util.containers.ConcurrentFactoryMap;
import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.containers.ConcurrentWeakValueHashMap;
import com.intellij.util.messages.MessageBusConnection;
@@ -81,6 +79,21 @@ public class FileManagerImpl implements FileManager {
private final ConcurrentMap<VirtualFile, PsiDirectory> myVFileToPsiDirMap = new ConcurrentHashMap<VirtualFile, PsiDirectory>();
private final ConcurrentWeakValueHashMap<VirtualFile, FileViewProvider> myVFileToViewProviderMap = new ConcurrentWeakValueHashMap<VirtualFile, FileViewProvider>();
private final Map<VirtualFile, GlobalSearchScope> myDefaultUseScopesCache = new ConcurrentFactoryMap<VirtualFile, GlobalSearchScope>() {
@Override
protected GlobalSearchScope create(VirtualFile key) {
GlobalSearchScope scope = getInherentResolveScope(key);
for (ResolveScopeEnlarger enlarger : ResolveScopeEnlarger.EP_NAME.getExtensions()) {
final SearchScope extra = enlarger.getAdditionalResolveScope(key, myManager.getProject());
if (extra != null) {
scope = scope.union(extra);
}
}
return scope;
}
};
private boolean myInitialized = false;
private boolean myDisposed = false;
@@ -108,6 +121,13 @@ public class FileManagerImpl implements FileManager {
recalcAllViewProviders();
}
});
manager.registerRunnableToRunOnChange(new Runnable() {
@Override
public void run() {
myDefaultUseScopesCache.clear();
}
});
}
public void processQueue() {
@@ -394,19 +414,7 @@ public class FileManagerImpl implements FileManager {
}
private GlobalSearchScope getDefaultResolveScope(@NotNull final Project project, @NotNull PsiFile psiFile, @NotNull final VirtualFile vFile) {
return CachedValuesManager.getManager(project).getCachedValue(psiFile, new CachedValueProvider<GlobalSearchScope>() {
@Override
public Result<GlobalSearchScope> compute() {
GlobalSearchScope scope = getInherentResolveScope(vFile);
for (ResolveScopeEnlarger enlarger : ResolveScopeEnlarger.EP_NAME.getExtensions()) {
final SearchScope extra = enlarger.getAdditionalResolveScope(vFile, project);
if (extra != null) {
scope = scope.union(extra);
}
}
return Result.create(scope, PsiModificationTracker.MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
}
});
return myDefaultUseScopesCache.get(vFile);
}
private GlobalSearchScope getInherentResolveScope(VirtualFile vFile) {
@@ -82,6 +82,10 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
cleared = true;
}
public List<Pair<Place, PsiFile>> getResult() {
return result;
}
@NotNull
public MultiHostRegistrar startInjecting(@NotNull Language language) {
escapers = new SmartList<LiteralTextEscaper<? extends PsiLanguageInjectionHost>>();
@@ -437,7 +437,7 @@ public class FileBasedIndex implements ApplicationComponent {
return index;
}
private static <K> PersistentHashMap<Integer, Collection<K>> createIdToDataKeysIndex(ID<K, ?> indexId,
private static <K> PersistentHashMap<Integer, Collection<K>> createIdToDataKeysIndex(final ID<K, ?> indexId,
final KeyDescriptor<K> keyDescriptor,
MemoryIndexStorage<K, ?> storage) throws IOException {
final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId);
@@ -446,19 +446,35 @@ public class FileBasedIndex implements ApplicationComponent {
final DataExternalizer<Collection<K>> dataExternalizer = new DataExternalizer<Collection<K>>() {
public void save(DataOutput out, Collection<K> value) throws IOException {
DataInputOutputUtil.writeINT(out, value.size());
for (K key : value) {
keyDescriptor.save(out, key);
try {
DataInputOutputUtil.writeINT(out, value.size());
for (K key : value) {
keyDescriptor.save(out, key);
}
}
catch (IOException e) {
throw e;
}
catch (IllegalArgumentException e) {
throw new IOException("Error saving data for index " + indexId, e);
}
}
public Collection<K> read(DataInput in) throws IOException {
final int size = DataInputOutputUtil.readINT(in);
final List<K> list = new ArrayList<K>();
for (int idx = 0; idx < size; idx++) {
list.add(keyDescriptor.read(in));
try {
final int size = DataInputOutputUtil.readINT(in);
final List<K> list = new ArrayList<K>();
for (int idx = 0; idx < size; idx++) {
list.add(keyDescriptor.read(in));
}
return list;
}
catch (IOException e) {
throw e;
}
catch (IllegalArgumentException e) {
throw new IOException("Error reading data for index " + indexId, e);
}
return list;
}
};
@@ -17,6 +17,7 @@ package com.intellij.openapi.components;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
@@ -98,4 +99,11 @@ public interface ComponentManager extends UserDataHolder, Disposable {
<T> T[] getExtensions(ExtensionPointName<T> extensionPointName);
ComponentConfig getConfig(Class componentImplementation);
/**
* @return condition for this component being disposed.
* see {@link com.intellij.openapi.application.Application#invokeLater(Runnable, Condition)} for the usage example.
*/
@NotNull
Condition getDisposed();
}
@@ -17,7 +17,6 @@ package com.intellij.openapi.project;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.extensions.AreaInstance;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -61,8 +60,6 @@ public interface Project extends ComponentManager, AreaInstance {
void save();
Condition getDisposed();
boolean isOpen();
boolean isInitialized();
@@ -33,7 +33,7 @@ public class ComboBoxWithWidePopup extends JComboBox {
if (SystemInfo.isMac && UIUtil.isUnderAquaLookAndFeel()) setMaximumRowCount(25);
}
public ComboBoxWithWidePopup(final Object items[]) {
public ComboBoxWithWidePopup(final Object[] items) {
super(items);
if (SystemInfo.isMac && UIUtil.isUnderAquaLookAndFeel()) setMaximumRowCount(25);
@@ -16,6 +16,7 @@
package com.intellij.codeInsight.hint;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
@@ -35,11 +36,13 @@ import java.awt.*;
import java.awt.image.BufferedImage;
public class EditorFragmentComponent extends JPanel {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.hint.EditorFragmentComponent");
private EditorFragmentComponent(EditorEx editor, int startLine, int endLine, boolean showFolding, boolean showGutter) {
Document doc = editor.getDocument();
final int endOffset = endLine < doc.getLineCount() ? doc.getLineEndOffset(endLine) : doc.getTextLength();
int textWidth = Math.min(editor.getMaxWidthInRange(doc.getLineStartOffset(startLine), endOffset), ScreenUtil.getScreenRectangle(1, 1).width);
LOG.assertTrue(textWidth > 0, "TextWidth: "+textWidth+"; startLine:" + startLine + "; endLine:" + endLine + ";");
FoldingModelEx foldingModel = editor.getFoldingModel();
boolean isFoldingEnabled = foldingModel.isFoldingEnabled();
@@ -51,6 +54,8 @@ public class EditorFragmentComponent extends JPanel {
Point p2 = editor.logicalPositionToXY(new LogicalPosition(Math.max(endLine, startLine + 1), 0));
int y1 = p1.y;
int y2 = p2.y;
int height = y2 - y1;
LOG.assertTrue(height > 0, "Height: " + height + "; startLine:" + startLine + "; endLine:" + endLine + "; p1:" + p1 + "; p2:" + p2);
int savedScrollOffset = editor.getScrollingModel().getHorizontalScrollOffset();
if (savedScrollOffset > 0) {
@@ -58,20 +63,20 @@ public class EditorFragmentComponent extends JPanel {
editor.getScrollingModel().scrollHorizontally(0);
}
final Image textImage = new BufferedImage(textWidth, y2 - y1, BufferedImage.TYPE_INT_RGB);
final Image textImage = new BufferedImage(textWidth, height, BufferedImage.TYPE_INT_RGB);
Graphics textGraphics = textImage.getGraphics();
final JComponent rowHeader;
final Image markersImage;
if (showGutter) {
rowHeader = editor.getGutterComponentEx();
markersImage = new BufferedImage(Math.max(1, rowHeader.getWidth()), y2 - y1, BufferedImage.TYPE_INT_RGB);
markersImage = new BufferedImage(Math.max(1, rowHeader.getWidth()), height, BufferedImage.TYPE_INT_RGB);
Graphics markerGraphics = markersImage.getGraphics();
markerGraphics.translate(0, -y1);
markerGraphics.setClip(0, y1, rowHeader.getWidth(), y2 - y1);
markerGraphics.setClip(0, y1, rowHeader.getWidth(), height);
markerGraphics.setColor(getBackgroundColor(editor));
markerGraphics.fillRect(0, y1, rowHeader.getWidth(), y2 - y1);
markerGraphics.fillRect(0, y1, rowHeader.getWidth(), height);
rowHeader.paint(markerGraphics);
}
else {
@@ -80,7 +85,7 @@ public class EditorFragmentComponent extends JPanel {
}
textGraphics.translate(0, -y1);
textGraphics.setClip(0, y1, textWidth, y2 - y1);
textGraphics.setClip(0, y1, textWidth, height);
final boolean wasVisible = editor.setCaretVisible(false);
editor.getContentComponent().paint(textGraphics);
if (wasVisible) {
@@ -153,7 +158,8 @@ public class EditorFragmentComponent extends JPanel {
Point p = new Point(x, y);
LightweightHint hint = new MyComponentHint(fragmentComponent);
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, (hideByAnyKey ? HintManagerImpl.HIDE_BY_ANY_KEY : 0) | HintManagerImpl.HIDE_BY_TEXT_CHANGE, 0, false, new HintHint(editor, p));
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, (hideByAnyKey ? HintManager.HIDE_BY_ANY_KEY : 0) |
HintManager.HIDE_BY_TEXT_CHANGE, 0, false, new HintHint(editor, p));
return hint;
}
@@ -44,11 +44,9 @@ public class ApplicationManagerEx extends ApplicationManager {
final Application old = ourApplication;
Disposer.register(parent, new Disposable() {
public void dispose() {
ourApplication = old;
CachedSingletonsRegistry.cleanupCachedFields();
setApplication(old);
}
});
ourApplication = instance;
CachedSingletonsRegistry.cleanupCachedFields();
setApplication(instance);
}
}
@@ -87,7 +87,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
private final EventDispatcher<ApplicationListener> myDispatcher = EventDispatcher.create(ApplicationListener.class);
private final boolean myTestModeFlag;
private boolean myTestModeFlag;
private final boolean myHeadlessMode;
private final boolean myCommandLineMode;
@@ -357,6 +357,10 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
return myTestModeFlag;
}
public void setUnitTestMode(boolean testModeFlag) {
myTestModeFlag = testModeFlag;
}
public boolean isHeadlessEnvironment() {
return myHeadlessMode;
}
@@ -689,7 +693,10 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
if (!canExit()) return;
if (disposeSelf()) System.exit(myExitCode);
boolean success = disposeSelf();
if (success && !isUnitTestMode()) {
System.exit(myExitCode);
}
}
};
@@ -19,16 +19,16 @@
*/
package com.intellij.openapi.application.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityInvokator;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import org.jetbrains.annotations.NotNull;
public class ModalityInvokatorImpl implements ModalityInvokator {
public ActionCallback invokeLater(Runnable runnable) {
return invokeLater(runnable, Conditions.FALSE);
return invokeLater(runnable, ApplicationManager.getApplication().getDisposed());
}
public ActionCallback invokeLater(final Runnable runnable, @NotNull final Condition expired) {
@@ -40,6 +40,6 @@ public class ModalityInvokatorImpl implements ModalityInvokator {
}
public ActionCallback invokeLater(Runnable runnable, @NotNull ModalityState state) {
return invokeLater(runnable, state, Conditions.FALSE);
return invokeLater(runnable, state, ApplicationManager.getApplication().getDisposed());
}
}
@@ -124,6 +124,7 @@ public class DummyProject extends UserDataHolderBase implements Project {
return false;
}
@NotNull
public Condition getDisposed() {
return new Condition() {
public boolean value(final Object o) {
@@ -30,6 +30,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.util.ArrayUtil;
@@ -75,6 +76,11 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
private Boolean myHeadless;
private ComponentsRegistry myComponentsRegistry = new ComponentsRegistry();
private boolean myHaveProgressManager = false;
private final Condition myDisposedCondition = new Condition() {
public boolean value(final Object o) {
return isDisposed();
}
};
protected ComponentManagerImpl(ComponentManager parentComponentManager) {
myParentComponentManager = parentComponentManager;
@@ -431,6 +437,11 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return myComponentsRegistry.getConfig(componentImplementation);
}
@NotNull
public Condition getDisposed() {
return myDisposedCondition;
}
private class ComponentsRegistry {
private final Map<Class, Object> myInterfaceToLockMap = new HashMap<Class, Object>();
private final Map<Class, Class> myInterfaceToClassMap = new HashMap<Class, Class>();
@@ -24,6 +24,8 @@
*/
package com.intellij.openapi.editor.actions;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
@@ -36,6 +38,14 @@ public class SimplePasteAction extends EditorAction {
super(new Handler());
}
@Override
public void update(AnActionEvent e) {
super.update(e);
if (ActionPlaces.isPopupPlace(e.getPlace())) {
e.getPresentation().setVisible(e.getPresentation().isEnabled());
}
}
private static class Handler extends EditorWriteActionHandler {
public void executeWriteAction(Editor editor, DataContext dataContext) {
if (editor.isColumnMode()) {
@@ -87,7 +87,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
private void releaseBulkCaretMarker() {
if (savedBeforeBulkCaretMarker != null) {
((RangeMarkerEx)savedBeforeBulkCaretMarker).dispose();
savedBeforeBulkCaretMarker.dispose();
savedBeforeBulkCaretMarker = null;
}
}
@@ -221,6 +221,14 @@ public class EditorsSplitters extends JPanel {
}
mySplittersElement = null;
}
// clear empty splitters
for (EditorWindow window : getWindows()) {
if (window.getEditors().length == 0) {
for (EditorWindow sibling : window.findSiblings()) {
sibling.unsplit(false);
}
}
}
}
}
@@ -228,6 +236,7 @@ public class EditorsSplitters extends JPanel {
mySplittersElement = element;
}
@Nullable
@SuppressWarnings({"HardCodedStringLiteral"})
public JPanel readExternalPanel(final Element element, @Nullable JPanel panel) {
final Element splitterElement = element.getChild("splitter");
@@ -263,11 +272,11 @@ public class EditorsSplitters extends JPanel {
} else {
window = findWindowWith(panel);
}
try {
//noinspection unchecked
final List<Element> children = leaf.getChildren("file");
VirtualFile currentFile = null;
for (final Element file : children) {
//noinspection unchecked
final List<Element> children = leaf.getChildren("file");
VirtualFile currentFile = null;
for (final Element file : children) {
try {
final HistoryEntry entry = new HistoryEntry(getManager().getProject(), file.getChild(HistoryEntry.TAG));
boolean isCurrent = Boolean.valueOf(file.getAttributeValue("current")).booleanValue();
getManager().openFileImpl3(window, entry.myFile, false, entry, isCurrent);
@@ -281,15 +290,15 @@ public class EditorsSplitters extends JPanel {
}
}
}
if (currentFile != null) {
final EditorComposite editor = window.findFileComposite(currentFile);
if (editor != null) {
window.setSelectedEditor(editor, true);
}
catch (InvalidDataException e) {
// OK
}
}
catch (InvalidDataException e) {
// OK
if (currentFile != null) {
final EditorComposite editor = window.findFileComposite(currentFile);
if (editor != null) {
window.setSelectedEditor(editor, true);
}
}
return window.myPanel;
}
@@ -44,7 +44,6 @@ import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.ex.MessagesEx;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -83,12 +82,6 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx {
public boolean myOptimiseTestLoadSpeed;
@NonNls public static final String TEMPLATE_PROJECT_NAME = "Default (Template) Project";
private final Condition myDisposedCondition = new Condition() {
public boolean value(final Object o) {
return isDisposed();
}
};
private String myName;
private String myOldName;
@@ -174,10 +167,6 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx {
return ProjectManagerEx.getInstanceEx().isProjectOpened(this);
}
public Condition getDisposed() {
return myDisposedCondition;
}
public boolean isInitialized() {
return isOpen() && !isDisposed() && StartupManagerEx.getInstanceEx(this).startupActivityPassed();
}
@@ -75,13 +75,13 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
}
public FileStatus calcStatus(@NotNull VirtualFile virtualFile) {
if (virtualFile.isInLocalFileSystem() && myFileStatusProvider != null) {
for (FileStatusProvider extension : myExtensions.getValue()) {
FileStatus status = extension.getFileStatus(virtualFile);
if (status != null) {
return status;
}
for (FileStatusProvider extension : myExtensions.getValue()) {
FileStatus status = extension.getFileStatus(virtualFile);
if (status != null) {
return status;
}
}
if (virtualFile.isInLocalFileSystem() && myFileStatusProvider != null) {
return myFileStatusProvider.getFileStatus(virtualFile);
} else {
return FileStatus.NOT_CHANGED;
@@ -114,7 +114,7 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
public void initComponent() { }
public void addFileStatusListener(FileStatusListener listener) {
public void addFileStatusListener(@NotNull FileStatusListener listener) {
myListeners.add(listener);
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.wm.impl;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
@@ -76,7 +77,8 @@ public final class CommandProcessor implements Runnable {
// max. I'm not actually quite sure this should have NON_MODAL modality but it should
// definitely have some since runnables in command list may (and do) request some PSI activity
final boolean queueNext = myCommandCount > 0;
ApplicationManager.getApplication().getInvokator().invokeLater(command, ModalityState.NON_MODAL, expire == null ? Condition.FALSE : expire).doWhenDone(new Runnable() {
Application application = ApplicationManager.getApplication();
application.getInvokator().invokeLater(command, ModalityState.NON_MODAL, expire == null ? application.getDisposed() : expire).doWhenDone(new Runnable() {
public void run() {
if (queueNext) {
CommandProcessor.this.run();
@@ -1823,7 +1823,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
@Nullable
public Condition getExpireCondition() {
return Condition.FALSE;
return ApplicationManager.getApplication().getDisposed();
}
}
@@ -24,9 +24,6 @@ import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.reference.SoftReference;
import com.intellij.util.concurrency.JBLock;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import gnu.trove.TLongArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,23 +32,12 @@ import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.util.ObjectUtils.*;
/**
* @author Dmitry Avdeev
*/
public abstract class CachedValueBase<T> {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.CachedValueImpl");
private final MyTimedReference<T> myData = new MyTimedReference<T>();
private final JBLock r;
private final JBLock w;
public CachedValueBase() {
JBReentrantReadWriteLock rw = LockFactory.createReadWriteLock();
r = rw.readLock();
w = rw.writeLock();
}
protected Data<T> computeData(T value, Object[] dependencies) {
if (dependencies == null) {
@@ -66,7 +52,7 @@ public abstract class CachedValueBase<T> {
}
protected void setValue(final T value, final CachedValueProvider.Result<T> result) {
myData.setData(computeData(value == null ? (T)NULL : value, getDependencies(result)));
myData.setData(computeData(value == null ? (T)ObjectUtils.NULL : value, getDependencies(result)));
myData.setIsLocked(result != null && result.isLockValue());
}
@@ -82,7 +68,8 @@ public abstract class CachedValueBase<T> {
}
else {
Object[] items = result.getDependencyItems();
return result.getValue() == null ? items : items == null ? new Object[] {result.getValue()}: ArrayUtil.append(items, result.getValue());
T value = result.getValue();
return value == null ? items : items == null ? new Object[] {value}: ArrayUtil.append(items, value);
}
}
@@ -133,7 +120,7 @@ public abstract class CachedValueBase<T> {
protected void collectDependencies(TLongArrayList timeStamps, List<Object> resultingDeps, Object[] dependencies) {
for (Object dependency : dependencies) {
if (dependency == null || dependency == NULL) continue;
if (dependency == null || dependency == ObjectUtils.NULL) continue;
if (dependency instanceof Object[]) {
collectDependencies(timeStamps, resultingDeps, (Object[])dependency);
}
@@ -168,16 +155,9 @@ public abstract class CachedValueBase<T> {
}
public T setValue(final CachedValueProvider.Result<T> result) {
w.lock();
try {
T value = result.getValue();
setValue(value, result);
return value;
}
finally {
w.unlock();
}
T value = result == null ? null : result.getValue();
setValue(value, result);
return value;
}
public abstract boolean isFromMyProject(Project project);
@@ -202,34 +182,15 @@ public abstract class CachedValueBase<T> {
@Nullable
protected <P> T getValueWithLock(P param) {
r.lock();
try {
T value = getUpToDateOrNull(true);
if (value != null) {
return value == NULL ? null : value;
}
}
finally {
r.unlock();
T value = getUpToDateOrNull(true);
if (value != null) {
return value == ObjectUtils.NULL ? null : value;
}
// compute outside lock to avoid deadlock
CachedValueProvider.Result<T> result = doCompute(param);
T computed = result == null ? null : result.getValue();
w.lock();
try {
//T value = getUpToDateOrNull(false);
//if (value != null) {
// return value == NULL ? null : value;
//}
setValue(computed, result);
return computed;
}
finally {
w.unlock();
}
return setValue(result);
}
protected abstract <P> CachedValueProvider.Result<T> doCompute(P param);
@@ -237,16 +198,15 @@ public abstract class CachedValueBase<T> {
private static class MyTimedReference<T> extends TimedReference<SoftReference<Data<T>>> {
private boolean myIsLocked;
public MyTimedReference() {
super(null);
}
public void setIsLocked(final boolean isLocked) {
public synchronized void setIsLocked(final boolean isLocked) {
myIsLocked = isLocked;
}
protected boolean isLocked() {
protected synchronized boolean isLocked() {
return super.isLocked() || myIsLocked;
}
@@ -1192,3 +1192,7 @@ action.ConvertIndentsToTabs.description=Convert the indentation in the file or s
group.Vcs.Import.text=Import into Version Control
group.Vcs.Browse.text=Browse VCS Repository
action.Graph.print.reset=Reset
action.MarkSourceRoot.text=Source Root
action.MarkTestSourceRoot.text=Test Source Root
action.MarkExcludeRoot.text=Excluded
group.MarkRootGroup.text=Mark Directory As
@@ -402,6 +402,11 @@
</group>
<group id="ProjectViewPopupMenuSettingsGroup">
<group id="MarkRootGroup" class="com.intellij.ide.projectView.actions.MarkRootGroup" popup="true">
<action id="MarkSourceRoot" class="com.intellij.ide.projectView.actions.MarkRootAction"/>
<action id="MarkTestSourceRoot" class="com.intellij.ide.projectView.actions.MarkTestSourceRootAction"/>
<action id="MarkExcludeRoot" class="com.intellij.ide.projectView.actions.MarkExcludeRootAction"/>
</group>
</group>
<group id="ProjectViewPopupMenu">
@@ -20,6 +20,7 @@ import com.intellij.openapi.components.BaseComponent;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.util.ArrayUtil;
@@ -149,4 +150,10 @@ public class MockComponentManager extends UserDataHolderBase implements Componen
public ComponentConfig getConfig(Class componentImplementation) {
throw new UnsupportedOperationException("Method getConfig not implemented in " + getClass());
}
@NotNull
@Override
public Condition getDisposed() {
return Condition.FALSE;
}
}
@@ -50,6 +50,7 @@ public class MockProject extends MockComponentManager implements ProjectEx {
return ServiceManager.getService(this, PomModel.class);
}
@NotNull
@Override
public Condition getDisposed() {
return new Condition() {
@@ -15,6 +15,8 @@
*/
package com.intellij.util.io;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
@@ -34,7 +36,7 @@ public class EnumeratorStringDescriptor implements KeyDescriptor<String> {
return val1.equals(val2);
}
public void save(final DataOutput storage, final String value) throws IOException {
public void save(final DataOutput storage, @NotNull final String value) throws IOException {
IOUtil.writeUTFFast(buffer, storage, value);
}
@@ -20,14 +20,13 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsBundle;
@@ -46,6 +45,7 @@ import java.util.ListIterator;
*/
public class LineStatusTracker {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.ex.LineStatusTracker");
private final Object myLock = new Object();
// true -> have contents
private BaseLoadState myBaseLoaded;
@@ -72,36 +72,36 @@ public class LineStatusTracker {
}
public void initialize(@NotNull final String upToDateContent) {
ApplicationManager.getApplication().isReadAccessAllowed();
ApplicationManager.getApplication().assertIsDispatchThread();
LOG.assertTrue(BaseLoadState.LOADING == myBaseLoaded);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
try {
myUpToDateDocument.setReadOnly(false);
myUpToDateDocument.replaceString(0, myUpToDateDocument.getTextLength(), upToDateContent);
myUpToDateDocument.setReadOnly(true);
reinstallRanges();
synchronized (myLock) {
try {
myUpToDateDocument.setReadOnly(false);
myUpToDateDocument.replaceString(0, myUpToDateDocument.getTextLength(), upToDateContent);
myUpToDateDocument.setReadOnly(true);
reinstallRanges();
if (myDocumentListener == null) {
myDocumentListener = new MyDocumentListener();
myDocument.addDocumentListener(myDocumentListener);
}
}
finally {
myBaseLoaded = BaseLoadState.LOADED;
if (myDocumentListener == null) {
myDocumentListener = new MyDocumentListener();
myDocument.addDocumentListener(myDocumentListener);
}
}
});
finally {
myBaseLoaded = BaseLoadState.LOADED;
}
}
}
private void reinstallRanges() {
myApplication.assertWriteAccessAllowed();
myApplication.assertReadAccessAllowed();
removeHighlightersFromMarkupModel();
myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges();
for (final Range range : myRanges) {
range.setHighlighter(createHighlighter(range));
synchronized (myLock) {
removeHighlightersFromMarkupModel();
myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges();
for (final Range range : myRanges) {
range.setHighlighter(createHighlighter(range));
}
}
}
@@ -137,16 +137,13 @@ public class LineStatusTracker {
}
public void release() {
myApplication.runWriteAction(new Runnable() {
@Override
public void run() {
if (myDocumentListener != null) {
myDocument.removeDocumentListener(myDocumentListener);
}
removeHighlightersFromMarkupModel();
myRanges.clear();
synchronized (myLock) {
if (myDocumentListener != null) {
myDocument.removeDocumentListener(myDocumentListener);
}
});
removeHighlightersFromMarkupModel();
myRanges.clear();
}
}
public Document getDocument() {
@@ -160,39 +157,38 @@ public class LineStatusTracker {
public List<Range> getRanges() {
myApplication.assertReadAccessAllowed();
return myRanges;
synchronized (myLock) {
return myRanges;
}
}
public Document getUpToDateDocument() {
myApplication.assertIsDispatchThread();
return myUpToDateDocument;
}
public void startBulkUpdate() {
myApplication.runWriteAction(new Runnable() {
@Override
public void run() {
myBulkUpdate = true;
removeHighlightersFromMarkupModel();
myRanges.clear();
}
});
synchronized (myLock) {
myBulkUpdate = true;
removeHighlightersFromMarkupModel();
myRanges.clear();
}
}
private void removeHighlightersFromMarkupModel() {
final MarkupModel markupModel = myDocument.getMarkupModel(myProject);
for (Range range : myRanges) {
markupModel.removeHighlighter(range.getHighlighter());
synchronized (myLock) {
for (Range range : myRanges) {
markupModel.removeHighlighter(range.getHighlighter());
}
}
}
public void finishBulkUpdate() {
myApplication.runWriteAction(new Runnable() {
@Override
public void run() {
myBulkUpdate = false;
reinstallRanges();
}
});
synchronized (myLock) {
myBulkUpdate = false;
reinstallRanges();
}
}
/**
@@ -200,24 +196,18 @@ public class LineStatusTracker {
* false -> load was already started; after contents is loaded,
*/
public boolean resetForBaseRevisionLoad() {
return myApplication.runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
if (BaseLoadState.LOADING == myBaseLoaded) return false;
return myApplication.runWriteAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
myUpToDateDocument.setReadOnly(false);
myUpToDateDocument.setText("");
myUpToDateDocument.setReadOnly(true);
removeHighlightersFromMarkupModel();
myRanges.clear();
myBaseLoaded = BaseLoadState.LOADING;
return true;
}
});
}
});
myApplication.assertReadAccessAllowed();
synchronized (myLock) {
if (BaseLoadState.LOADING == myBaseLoaded) return false;
myUpToDateDocument.setReadOnly(false);
myUpToDateDocument.setText("");
myUpToDateDocument.setReadOnly(true);
removeHighlightersFromMarkupModel();
myRanges.clear();
myBaseLoaded = BaseLoadState.LOADING;
return true;
}
}
private class MyDocumentListener extends DocumentAdapter {
@@ -231,39 +221,41 @@ public class LineStatusTracker {
if (myBulkUpdate || (BaseLoadState.LOADED != myBaseLoaded)) return;
myApplication.assertWriteAccessAllowed();
try {
myFirstChangedLine = myDocument.getLineNumber(e.getOffset());
myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++;
synchronized (myLock) {
try {
myFirstChangedLine = myDocument.getLineNumber(e.getOffset());
myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++;
myLinesBeforeChange = myDocument.getLineNumber(e.getOffset() + e.getOldLength()) - myDocument.getLineNumber(e.getOffset());
myLinesBeforeChange = myDocument.getLineNumber(e.getOffset() + e.getOldLength()) - myDocument.getLineNumber(e.getOffset());
Range firstChangedRange = getLastRangeBeforeLine(myFirstChangedLine);
Range firstChangedRange = getLastRangeBeforeLine(myFirstChangedLine);
if (firstChangedRange == null) {
myUpToDateFirstLine = myFirstChangedLine;
}
else if (firstChangedRange.containsLine(myFirstChangedLine)) {
myFirstChangedLine = firstChangedRange.getOffset1();
myUpToDateFirstLine = firstChangedRange.getUOffset1();
}
else {
myUpToDateFirstLine = firstChangedRange.getUOffset2() + (myFirstChangedLine - firstChangedRange.getOffset2());
}
if (firstChangedRange == null) {
myUpToDateFirstLine = myFirstChangedLine;
}
else if (firstChangedRange.containsLine(myFirstChangedLine)) {
myFirstChangedLine = firstChangedRange.getOffset1();
myUpToDateFirstLine = firstChangedRange.getUOffset1();
}
else {
myUpToDateFirstLine = firstChangedRange.getUOffset2() + (myFirstChangedLine - firstChangedRange.getOffset2());
}
Range myLastChangedRange = getLastRangeBeforeLine(myLastChangedLine);
Range myLastChangedRange = getLastRangeBeforeLine(myLastChangedLine);
if (myLastChangedRange == null) {
myUpToDateLastLine = myLastChangedLine;
if (myLastChangedRange == null) {
myUpToDateLastLine = myLastChangedLine;
}
else if (myLastChangedRange.containsLine(myLastChangedLine)) {
myUpToDateLastLine = myLastChangedRange.getUOffset2();
myLastChangedLine = myLastChangedRange.getOffset2();
}
else {
myUpToDateLastLine = myLastChangedRange.getUOffset2() + (myLastChangedLine - myLastChangedRange.getOffset2());
}
} catch (ProcessCanceledException ignore) {
}
else if (myLastChangedRange.containsLine(myLastChangedLine)) {
myUpToDateLastLine = myLastChangedRange.getUOffset2();
myLastChangedLine = myLastChangedRange.getOffset2();
}
else {
myUpToDateLastLine = myLastChangedRange.getUOffset2() + (myLastChangedLine - myLastChangedRange.getOffset2());
}
} catch (ProcessCanceledException ignore) {
}
}
@@ -281,47 +273,49 @@ public class LineStatusTracker {
if (myBulkUpdate || (BaseLoadState.LOADED != myBaseLoaded)) return;
myApplication.assertWriteAccessAllowed();
try {
synchronized (myLock) {
try {
int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
int linesAfterChange = line - myDocument.getLineNumber(e.getOffset());
int linesShift = linesAfterChange - myLinesBeforeChange;
int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
int linesAfterChange = line - myDocument.getLineNumber(e.getOffset());
int linesShift = linesAfterChange - myLinesBeforeChange;
List<Range> rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine);
List<Range> rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine);
List<Range> rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine);
List<Range> rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine);
List<Range> changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine);
List<Range> changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine);
int newSize = rangesBeforeChange.size() + changedRanges.size() + rangesAfterChange.size();
if (myRanges.size() != newSize) {
LOG.info("Ranges: " + myRanges + "; first changed line: " + myFirstChangedLine + "; last changed line: " + myLastChangedLine);
LOG.assertTrue(false);
}
myLastChangedLine += linesShift;
List<Range> newChangedRanges = getNewChangedRanges();
shiftRanges(rangesAfterChange, linesShift);
if (!changedRanges.equals(newChangedRanges)) {
replaceRanges(changedRanges, newChangedRanges);
myRanges = new ArrayList<Range>();
myRanges.addAll(rangesBeforeChange);
myRanges.addAll(newChangedRanges);
myRanges.addAll(rangesAfterChange);
myRanges = mergeRanges(myRanges);
for (Range range : myRanges) {
if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
int newSize = rangesBeforeChange.size() + changedRanges.size() + rangesAfterChange.size();
if (myRanges.size() != newSize) {
LOG.info("Ranges: " + myRanges + "; first changed line: " + myFirstChangedLine + "; last changed line: " + myLastChangedLine);
LOG.assertTrue(false);
}
myLastChangedLine += linesShift;
List<Range> newChangedRanges = getNewChangedRanges();
shiftRanges(rangesAfterChange, linesShift);
if (!changedRanges.equals(newChangedRanges)) {
replaceRanges(changedRanges, newChangedRanges);
myRanges = new ArrayList<Range>();
myRanges.addAll(rangesBeforeChange);
myRanges.addAll(newChangedRanges);
myRanges.addAll(rangesAfterChange);
myRanges = mergeRanges(myRanges);
for (Range range : myRanges) {
if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
}
}
} catch (ProcessCanceledException ignore) {
}
} catch (ProcessCanceledException ignore) {
}
}
@@ -390,49 +384,57 @@ public class LineStatusTracker {
@Nullable
Range getNextRange(final Range range) {
final int index = myRanges.indexOf(range);
if (index == myRanges.size() - 1) return null;
return myRanges.get(index + 1);
synchronized (myLock) {
final int index = myRanges.indexOf(range);
if (index == myRanges.size() - 1) return null;
return myRanges.get(index + 1);
}
}
@Nullable
Range getPrevRange(final Range range) {
final int index = myRanges.indexOf(range);
if (index <= 0) return null;
return myRanges.get(index - 1);
synchronized (myLock) {
final int index = myRanges.indexOf(range);
if (index <= 0) return null;
return myRanges.get(index - 1);
}
}
@Nullable
public Range getNextRange(final int line) {
final Range currentRange = getRangeForLine(line);
if (currentRange != null) {
return getNextRange(currentRange);
}
for (final Range range : myRanges) {
if (line > range.getOffset1() || line > range.getOffset2()) {
continue;
synchronized (myLock) {
final Range currentRange = getRangeForLine(line);
if (currentRange != null) {
return getNextRange(currentRange);
}
return range;
for (final Range range : myRanges) {
if (line > range.getOffset1() || line > range.getOffset2()) {
continue;
}
return range;
}
return null;
}
return null;
}
@Nullable
public Range getPrevRange(final int line) {
final Range currentRange = getRangeForLine(line);
if (currentRange != null) {
return getPrevRange(currentRange);
}
for (ListIterator<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
final Range range = iterator.previous();
if (range.getOffset1() > line) {
continue;
synchronized (myLock) {
final Range currentRange = getRangeForLine(line);
if (currentRange != null) {
return getPrevRange(currentRange);
}
return range;
for (ListIterator<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
final Range range = iterator.previous();
if (range.getOffset1() > line) {
continue;
}
return range;
}
return null;
}
return null;
}
public static List<Range> getRangesBefore(List<Range> ranges, int line) {
@@ -455,43 +457,49 @@ public class LineStatusTracker {
@Nullable
public Range getRangeForLine(final int line) {
for (final Range range : myRanges) {
if (range.getType() == Range.DELETED && line == range.getOffset1()) {
return range;
}
else if (line >= range.getOffset1() && line < range.getOffset2()) {
return range;
synchronized (myLock) {
for (final Range range : myRanges) {
if (range.getType() == Range.DELETED && line == range.getOffset1()) {
return range;
}
else if (line >= range.getOffset1() && line < range.getOffset2()) {
return range;
}
}
return null;
}
return null;
}
public void rollbackChanges(final Range range) {
myApplication.assertWriteAccessAllowed();
TextRange currentTextRange = getCurrentTextRange(range);
synchronized (myLock) {
TextRange currentTextRange = getCurrentTextRange(range);
if (range.getType() == Range.INSERTED) {
myDocument
.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), "");
}
else if (range.getType() == Range.DELETED) {
String upToDateContent = getUpToDateContent(range);
myDocument.insertString(currentTextRange.getStartOffset(), upToDateContent);
}
else {
if (range.getType() == Range.INSERTED) {
myDocument
.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), "");
}
else if (range.getType() == Range.DELETED) {
String upToDateContent = getUpToDateContent(range);
myDocument.insertString(currentTextRange.getStartOffset(), upToDateContent);
}
else {
String upToDateContent = getUpToDateContent(range);
myDocument.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()),
upToDateContent);
String upToDateContent = getUpToDateContent(range);
myDocument.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()),
upToDateContent);
}
}
}
public String getUpToDateContent(Range range) {
TextRange textRange = getUpToDateRange(range);
final int startOffset = textRange.getStartOffset();
final int endOffset = Math.min(textRange.getEndOffset() + 1, myUpToDateDocument.getTextLength());
return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
synchronized (myLock) {
TextRange textRange = getUpToDateRange(range);
final int startOffset = textRange.getStartOffset();
final int endOffset = Math.min(textRange.getEndOffset() + 1, myUpToDateDocument.getTextLength());
return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
}
}
Project getProject() {
@@ -539,7 +547,7 @@ public class LineStatusTracker {
}
public static LineStatusTracker createOn(final Document doc, final Project project) {
final Document document = EditorFactory.getInstance().createDocument("");
final Document document = new DocumentImpl(true);
return new LineStatusTracker(doc, document, project);
}
@@ -548,8 +556,9 @@ public class LineStatusTracker {
}
public void baseRevisionLoadFailed() {
myApplication.assertWriteAccessAllowed();
myBaseLoaded = BaseLoadState.FAILED;
synchronized (myLock) {
myBaseLoaded = BaseLoadState.FAILED;
}
}
public static enum BaseLoadState {
@@ -42,7 +42,6 @@ import com.intellij.openapi.editor.ex.DocumentBulkUpdateListener;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
@@ -68,6 +67,7 @@ import java.util.Map;
public class LineStatusTrackerManager implements ProjectComponent, LineStatusTrackerManagerI {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.LineStatusTrackerManager");
public final Object myLock = new Object();
public static LineStatusTrackerManagerI getInstance(final Project project) {
if (System.getProperty(IGNORE_CHANGEMARKERS_KEY) != null) {
@@ -116,15 +116,17 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
myDisposable = new Disposable() {
@Override
public void dispose() {
final Collection<LineStatusTracker> trackers = myLineStatusTrackers.values();
final LineStatusTracker[] lineStatusTrackers = trackers.toArray(new LineStatusTracker[trackers.size()]);
for (final LineStatusTracker tracker : lineStatusTrackers) {
releaseTracker(tracker.getDocument());
}
synchronized (myLock) {
final Collection<LineStatusTracker> trackers = myLineStatusTrackers.values();
final LineStatusTracker[] lineStatusTrackers = trackers.toArray(new LineStatusTracker[trackers.size()]);
for (final LineStatusTracker tracker : lineStatusTrackers) {
releaseTracker(tracker.getDocument());
}
myLineStatusTrackers.clear();
assert myLineStatusUpdateAlarms.isEmpty();
myLineStatusUpdateAlarms.clear();
myLineStatusTrackers.clear();
assert myLineStatusUpdateAlarms.isEmpty();
myLineStatusUpdateAlarms.clear();
}
}
};
Disposer.register(myProject, myDisposable);
@@ -178,12 +180,15 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
@Override
public LineStatusTracker getLineStatusTracker(final Document document) {
myApplication.assertReadAccessAllowed();
if ((! myProject.isOpen()) || myProject.isDisposed()) return null;
return myLineStatusTrackers.get(document);
synchronized (myLock) {
return myLineStatusTrackers.get(document);
}
}
private void resetTracker(@NotNull final VirtualFile virtualFile) {
myApplication.assertReadAccessAllowed();
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
final Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
@@ -194,49 +199,43 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
log("resetting tracker for file " + virtualFile.getPath());
final LineStatusTracker tracker = myLineStatusTrackers.get(document);
final boolean editorOpened = myFileEditorManager.isFileOpen(virtualFile);
final boolean shouldBeInstalled = shouldBeInstalled(virtualFile) && editorOpened;
if (tracker == null && (! shouldBeInstalled)) return;
synchronized (myLock) {
final LineStatusTracker tracker = myLineStatusTrackers.get(document);
myApplication.runWriteAction(new Runnable() {
@Override
public void run() {
// remove ?
if (tracker != null) {
if (! shouldBeInstalled) {
releaseTracker(document);
return;
} else if ((LineStatusTracker.BaseLoadState.LOADING == tracker.getBaseLoaded())) {
return; // will be recalculated
} else {
tracker.resetForBaseRevisionLoad();
startAlarm(document, virtualFile);
}
} else if (shouldBeInstalled) {
installTracker(virtualFile, document);
if (tracker == null && (! shouldBeInstalled)) return;
if (tracker != null) {
if (! shouldBeInstalled) {
releaseTracker(document);
return;
} else if ((LineStatusTracker.BaseLoadState.LOADING == tracker.getBaseLoaded())) {
return; // will be recalculated
} else {
tracker.resetForBaseRevisionLoad();
startAlarm(document, virtualFile);
}
} else if (shouldBeInstalled) {
installTracker(virtualFile, document);
}
});
}
}
private void releaseTracker(final Document document) {
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
myApplication.runWriteAction(new Runnable() {
@Override
public void run() {
final Alarm alarm = myLineStatusUpdateAlarms.remove(document);
if (alarm != null) {
alarm.cancelAllRequests();
}
final LineStatusTracker tracker = myLineStatusTrackers.remove(document);
if (tracker != null) {
tracker.release();
}
synchronized (myLock) {
final Alarm alarm = myLineStatusUpdateAlarms.remove(document);
if (alarm != null) {
alarm.cancelAllRequests();
}
});
final LineStatusTracker tracker = myLineStatusTrackers.remove(document);
if (tracker != null) {
tracker.release();
}
}
}
private boolean shouldBeInstalled(final VirtualFile virtualFile) {
@@ -261,25 +260,24 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
}
private void installTracker(final VirtualFile virtualFile, final Document document) {
myApplication.runWriteAction(new Runnable() {
@Override
public void run() {
if (myLineStatusTrackers.containsKey(document)) return;
assert !myLineStatusUpdateAlarms.containsKey(document);
synchronized (myLock) {
if (myLineStatusTrackers.containsKey(document)) return;
assert !myLineStatusUpdateAlarms.containsKey(document);
final LineStatusTracker tracker = LineStatusTracker.createOn(document, myProject);
myLineStatusTrackers.put(document, tracker);
final LineStatusTracker tracker = LineStatusTracker.createOn(document, myProject);
myLineStatusTrackers.put(document, tracker);
startAlarm(document, virtualFile);
}
});
startAlarm(document, virtualFile);
}
}
private void startAlarm(final Document document, final VirtualFile virtualFile) {
myApplication.assertWriteAccessAllowed();
myApplication.assertReadAccessAllowed();
final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
myLineStatusUpdateAlarms.put(document, alarm);
synchronized (myLock) {
myLineStatusUpdateAlarms.put(document, alarm);
}
alarm.addRequest(new BaseRevisionLoader(alarm, document, virtualFile), 10);
}
@@ -297,14 +295,12 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
@Override
public void run() {
myAlarm.cancelAllRequests();
final Boolean removed = myApplication.runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
final Alarm removed = myLineStatusUpdateAlarms.remove(myDocument);
return removed != null;
synchronized (myLock) {
final Alarm removed = myLineStatusUpdateAlarms.remove(myDocument);
if (removed == null) {
return;
}
});
if (! Boolean.TRUE.equals(removed)) return;
}
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
if (! myVirtualFile.isValid()) {
@@ -323,15 +319,13 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
final String converted = StringUtil.convertLineSeparators(lastUpToDateContent);
myApplication.invokeLater(new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
log("initializing tracker for file " + myVirtualFile.getPath());
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
if (tracker != null) {
tracker.initialize(converted);
}
synchronized (myLock) {
log("initializing tracker for file " + myVirtualFile.getPath());
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
if (tracker != null) {
tracker.initialize(converted);
}
});
}
}
}, new Condition() {
@Override
@@ -342,24 +336,13 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
}
private void reportTrackerBaseLoadFailed() {
myApplication.invokeLater(new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
log("base revision load failed for file " + myVirtualFile.getPath());
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
if (tracker != null) {
tracker.baseRevisionLoadFailed();
}
}
});
synchronized (myLock) {
log("base revision load failed for file " + myVirtualFile.getPath());
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
if (tracker != null) {
tracker.baseRevisionLoadFailed();
}
}, new Condition() {
@Override
public boolean value(final Object ignore) {
return (! myProject.isOpen()) || myProject.isDisposed();
}
});
}
}
}
@@ -369,7 +352,6 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
final VirtualFile[] openFiles = myFileEditorManager.getOpenFiles();
for(final VirtualFile openFile: openFiles) {
// write action inside is sufficient level
resetTracker(openFile);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,22 +27,26 @@ import org.jetbrains.annotations.NotNull;
public class InfiniteLoopStatementInspection extends BaseInspection {
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"infinite.loop.statement.display.name");
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"infinite.loop.statement.problem.descriptor");
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new InfiniteLoopStatementsVisitor();
}
@@ -50,12 +54,14 @@ public class InfiniteLoopStatementInspection extends BaseInspection {
private static class InfiniteLoopStatementsVisitor
extends BaseInspectionVisitor {
@Override public void visitForStatement(@NotNull PsiForStatement statement) {
@Override public void visitForStatement(
@NotNull PsiForStatement statement) {
super.visitForStatement(statement);
checkStatement(statement);
}
@Override public void visitWhileStatement(@NotNull PsiWhileStatement statement) {
@Override public void visitWhileStatement(
@NotNull PsiWhileStatement statement) {
super.visitWhileStatement(statement);
checkStatement(statement);
}
@@ -103,14 +103,16 @@ public class ControlFlowUtils{
final PsiExpression test = loopStatement.getCondition();
final PsiStatement body = loopStatement.getBody();
return statementMayCompleteNormally(body) && !BoolUtils.isTrue(test)
|| statementIsBreakTarget(loopStatement);
|| statementIsBreakTarget(loopStatement)
|| statementContainsContinueToAncestor(loopStatement);
}
private static boolean whileStatementMayReturnNormally(
@NotNull PsiWhileStatement loopStatement){
final PsiExpression test = loopStatement.getCondition();
return !BoolUtils.isTrue(test)
|| statementIsBreakTarget(loopStatement);
|| statementIsBreakTarget(loopStatement)
|| statementContainsContinueToAncestor(loopStatement);
}
private static boolean forStatementMayReturnNormally(
@@ -119,6 +121,9 @@ public class ControlFlowUtils{
if(statementIsBreakTarget(loopStatement)){
return true;
}
if (statementContainsContinueToAncestor(loopStatement)) {
return true;
}
if(test == null){
return false;
}
@@ -276,6 +281,19 @@ public class ControlFlowUtils{
return breakFinder.breakFound();
}
private static boolean statementContainsContinueToAncestor(
@NotNull PsiStatement statement){
PsiElement parent = statement.getParent();
while (parent instanceof PsiLabeledStatement) {
statement = (PsiStatement) parent;
parent = parent.getParent();
}
final ContinueToAncestorFinder continueToAncestorFinder =
new ContinueToAncestorFinder(statement);
statement.accept(continueToAncestorFinder);
return continueToAncestorFinder.continueToAncestorFound();
}
public static boolean statementContainsReturn(
@NotNull PsiStatement statement){
final ReturnFinder returnFinder = new ReturnFinder();
@@ -693,4 +711,41 @@ public class ControlFlowUtils{
containsCallToMethod = true;
}
}
private static class ContinueToAncestorFinder
extends JavaRecursiveElementVisitor {
private final PsiStatement statement;
private boolean found = false;
public ContinueToAncestorFinder(PsiStatement statement) {
this.statement = statement;
}
@Override
public void visitContinueStatement(
PsiContinueStatement continueStatement) {
if (found) {
return;
}
super.visitContinueStatement(continueStatement);
final PsiIdentifier labelIdentifier =
continueStatement.getLabelIdentifier();
if (labelIdentifier == null) {
return;
}
final PsiStatement continuedStatement =
continueStatement.findContinuedStatement();
if (continuedStatement == null) {
return;
}
if (PsiTreeUtil.isAncestor(continuedStatement, statement, true)) {
found = true;
}
}
public boolean continueToAncestorFound() {
return found;
}
}
}
@@ -94,13 +94,13 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection
extends BaseInspectionVisitor {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
final PsiElement parent = expression.getParent();
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);
final PsiElement parent = reference.getParent();
if (parent instanceof PsiImportStatement) {
return;
}
final PsiElement qualifier = expression.getQualifier();
final PsiElement qualifier = reference.getQualifier();
if (!(qualifier instanceof PsiJavaCodeReferenceElement)) {
return;
}
@@ -110,7 +110,7 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection
if (!(qualifierTarget instanceof PsiClass)) {
return;
}
final PsiElement target = expression.resolve();
final PsiElement target = reference.resolve();
if (!(target instanceof PsiClass)) {
return;
}
@@ -123,7 +123,7 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection
return;
}
final String shortName = aClass.getName();
if (!isReferenceToTargetClass(shortName, aClass, expression)) {
if (!isReferenceToTargetClass(shortName, aClass, reference)) {
return;
}
registerError(qualifier, aClass);
@@ -261,13 +261,13 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection {
extends BaseInspectionVisitor {
@Override
public void visitReferenceExpression(
PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
if (expression.isQualified()) {
public void visitReferenceElement(
PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);
if (reference.isQualified()) {
return;
}
final PsiElement target = expression.resolve();
final PsiElement target = reference.resolve();
if (!(target instanceof PsiClass)) {
return;
}
@@ -276,7 +276,7 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection {
if (containingClass == null) {
return;
}
registerError(expression, containingClass.getName());
registerError(reference, containingClass.getName());
}
}
}

Some files were not shown because too many files have changed in this diff Show More