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

Pull request accepted
This commit is contained in:
Max Medvedev
2015-09-02 15:58:05 +03:00
55 changed files with 784 additions and 221 deletions
@@ -71,7 +71,7 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder {
return null;
}
private class SurroundWithCastWorker extends RuntimeTypeEvaluator {
private static class SurroundWithCastWorker extends RuntimeTypeEvaluator {
private final Editor myEditor;
public SurroundWithCastWorker(Editor editor, PsiExpression expression, DebuggerContextImpl context, final ProgressIndicator indicator) {
@@ -80,7 +80,7 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder {
}
@Override
protected void typeCalculationFinished(@Nullable final PsiClass type) {
protected void typeCalculationFinished(@Nullable final PsiType type) {
if (type == null) {
return;
}
@@ -94,9 +94,9 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder {
try {
PsiElementFactory factory = JavaPsiFacade.getInstance(myElement.getProject()).getElementFactory();
PsiParenthesizedExpression parenth =
(PsiParenthesizedExpression)factory.createExpressionFromText("((" + type.getQualifiedName() + ")expr)", null);
PsiTypeCastExpression cast = (PsiTypeCastExpression)parenth.getExpression();
cast.getOperand().replace(myElement);
(PsiParenthesizedExpression)factory.createExpressionFromText("((" + type.getCanonicalText() + ")expr)", null);
//noinspection ConstantConditions
((PsiTypeCastExpression)parenth.getExpression()).getOperand().replace(myElement);
parenth = (PsiParenthesizedExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(parenth);
PsiExpression expr = (PsiExpression)myElement.replace(parenth);
TextRange range = expr.getTextRange();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -19,6 +19,7 @@ import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.DebuggerInvocationUtil;
import com.intellij.debugger.EvaluatingComputable;
import com.intellij.debugger.engine.ContextUtil;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
@@ -33,7 +34,6 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.sun.jdi.ClassType;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.Type;
@@ -43,13 +43,13 @@ import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<PsiClass> {
public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<PsiType> {
public RuntimeTypeEvaluator(@Nullable Editor editor, PsiElement expression, DebuggerContextImpl context, final ProgressIndicator indicator) {
super(editor, expression, context, indicator);
}
public void threadAction() {
PsiClass type = null;
PsiType type = null;
try {
type = evaluate();
}
@@ -62,10 +62,10 @@ public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<PsiCl
}
}
protected abstract void typeCalculationFinished(@Nullable PsiClass type);
protected abstract void typeCalculationFinished(@Nullable PsiType type);
@Nullable
protected PsiClass evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
protected PsiType evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
final Project project = evaluationContext.getProject();
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
@@ -82,36 +82,37 @@ public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<PsiCl
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.surrounded.expression.null"));
}
public static PsiClass getCastableRuntimeType(Project project, Value value) {
@Nullable
public static PsiType getCastableRuntimeType(Project project, Value value) {
Type type = value.type();
PsiClass psiClass = findPsiClass(project, type);
if (psiClass != null) {
return psiClass;
PsiType psiType = findPsiType(project, type);
if (psiType != null) {
return psiType;
}
if (type instanceof ClassType) {
ClassType superclass = ((ClassType)type).superclass();
if (superclass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(superclass.name())) {
psiClass = findPsiClass(project, superclass);
if (psiClass != null) {
return psiClass;
psiType = findPsiType(project, superclass);
if (psiType != null) {
return psiType;
}
}
for (InterfaceType interfaceType : ((ClassType)type).interfaces()) {
psiClass = findPsiClass(project, interfaceType);
if (psiClass != null) {
return psiClass;
psiType = findPsiType(project, interfaceType);
if (psiType != null) {
return psiType;
}
}
}
return null;
}
private static PsiClass findPsiClass(Project project, Type type) {
private static PsiType findPsiType(Project project, Type type) {
AccessToken token = ReadAction.start();
try {
return JavaPsiFacade.getInstance(project).findClass(type.name().replace('$', '.'), GlobalSearchScope.allScope(project));
return DebuggerUtils.getType(type.name().replace('$', '.'), project);
}
finally {
token.finish();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -92,11 +92,11 @@ public class DefaultCodeFragmentFactory extends CodeFragmentFactory {
if (debuggerSession != null) {
final Semaphore semaphore = new Semaphore();
semaphore.down();
final AtomicReference<PsiClass> nameRef = new AtomicReference<PsiClass>();
final AtomicReference<PsiType> nameRef = new AtomicReference<PsiType>();
final RuntimeTypeEvaluator worker =
new RuntimeTypeEvaluator(null, expression, debuggerContext, ProgressManager.getInstance().getProgressIndicator()) {
@Override
protected void typeCalculationFinished(@Nullable PsiClass type) {
protected void typeCalculationFinished(@Nullable PsiType type) {
nameRef.set(type);
semaphore.up();
}
@@ -106,10 +106,7 @@ public class DefaultCodeFragmentFactory extends CodeFragmentFactory {
ProgressManager.checkCanceled();
if (semaphore.waitFor(20)) break;
}
final PsiClass psiClass = nameRef.get();
if (psiClass != null) {
return JavaPsiFacade.getElementFactory(project).createType(psiClass);
}
return nameRef.get();
}
return null;
}
@@ -219,16 +219,17 @@ public class DebuggerTreeNodeExpression {
Project project = expression.getProject();
PsiClass type = RuntimeTypeEvaluator.getCastableRuntimeType(project, value);
PsiType type = RuntimeTypeEvaluator.getCastableRuntimeType(project, value);
if (type == null) {
return expression;
}
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
String typeName = type.getQualifiedName();
String typeName = type.getCanonicalText();
try {
PsiParenthesizedExpression parenthExpression = (PsiParenthesizedExpression)elementFactory.createExpressionFromText(
"((" + typeName + ")expression)", null);
//noinspection ConstantConditions
((PsiTypeCastExpression)parenthExpression.getExpression()).getOperand().replace(expression);
Set<String> imports = expression.getUserData(ADDITIONAL_IMPORTS_KEY);
if (imports == null) {
@@ -158,16 +158,21 @@ public class ClassRenderer extends NodeRendererImpl{
final ObjectReference objRef = (ObjectReference)value;
final ReferenceType refType = objRef.referenceType();
// default ObjectReference processing
final List<Field> fields = refType.allFields();
if (fields.size() > 0) {
for (final Field field : fields) {
if (!shouldDisplay(evaluationContext, objRef, field)) {
continue;
List<Field> fields = refType.allFields();
if (!fields.isEmpty()) {
boolean empty = true;
for (Field field : fields) {
if (shouldDisplay(evaluationContext, objRef, field)) {
children.add(nodeManager.createNode(
createFieldDescriptor(parentDescriptor, nodeDescriptorFactory, objRef, field, evaluationContext), evaluationContext));
empty = false;
}
children.add(nodeManager.createNode(createFieldDescriptor(parentDescriptor, nodeDescriptorFactory, objRef, field, evaluationContext), evaluationContext));
}
if (XDebuggerSettingsManager.getInstance().getDataViewSettings().isSortValues()) {
if (empty) {
children.add(nodeManager.createMessageNode(DebuggerBundle.message("message.node.class.no.fields.to.display")));
}
else if (XDebuggerSettingsManager.getInstance().getDataViewSettings().isSortValues()) {
Collections.sort(children, NodeManagerImpl.getNodeComparator());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -36,15 +36,15 @@ public class GutterIconTooltipHelper {
private GutterIconTooltipHelper() {
}
public static String composeText(@NotNull PsiElement[] elements, String start, final String pattern) {
public static String composeText(@NotNull PsiElement[] elements, @NotNull String start, @NotNull String pattern) {
return composeText(Arrays.asList(elements), start, pattern);
}
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, String start, final String pattern) {
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, @NotNull String start, @NotNull String pattern) {
return composeText(elements, start, pattern, "");
}
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, String start, final String pattern, String postfix) {
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, @NotNull String start, @NotNull String pattern, @NotNull String postfix) {
@NonNls StringBuilder result = new StringBuilder();
result.append("<html><body>");
result.append(start);
@@ -15,6 +15,8 @@
*/
package com.intellij.psi.impl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.MethodSignature;
@@ -64,11 +66,12 @@ public class FindSuperElementsHelper {
}
public static PsiMethod getSiblingInheritedViaSubClass(@NotNull PsiMethod method) {
return getSiblingInheritedViaSubClass(method, createSubClassCache());
return Pair.getFirst(getSiblingInheritedViaSubClass(method, createSubClassCache()));
}
public static PsiMethod getSiblingInheritedViaSubClass(@NotNull final PsiMethod method,
@NotNull Map<PsiClass, PsiClass> subClassCache) {
// returns super method, sub class
public static Pair<PsiMethod, PsiClass> getSiblingInheritedViaSubClass(@NotNull final PsiMethod method,
@NotNull Map<PsiClass, PsiClass> subClassCache) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return null;
if (method.hasModifierProperty(PsiModifier.STATIC)) return null;
final PsiClass containingClass = method.getContainingClass();
@@ -77,7 +80,7 @@ public class FindSuperElementsHelper {
return null;
}
final Collection<PsiAnchor> checkedInterfaces = new THashSet<PsiAnchor>();
final PsiMethod[] result = new PsiMethod[1];
final Ref<Pair<PsiMethod, PsiClass>> result = Ref.create();
ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true, true, false).forEach(new Processor<PsiClass>() {
@Override
public boolean process(PsiClass inheritor) {
@@ -107,14 +110,14 @@ public class FindSuperElementsHelper {
if (!isOverridden) {
continue;
}
result[0] = superMethod;
result.set(Pair.create(superMethod, inheritor));
return false;
}
}
return true;
}
});
return result[0];
return result.get();
}
@NotNull
@@ -184,12 +184,14 @@ public class JavaLineMarkerProvider implements LineMarkerProvider {
boolean canHaveSiblingSuper = !method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.STATIC) && method.hasModifierProperty(PsiModifier.PUBLIC)&& !method.hasModifierProperty(PsiModifier.FINAL)&& !method.hasModifierProperty(PsiModifier.NATIVE);
if (!canHaveSiblingSuper) continue;
PsiMethod siblingInheritedViaSubClass = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache);
PsiMethod siblingInheritedViaSubClass = Pair.getFirst(FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache));
if (siblingInheritedViaSubClass == null) {
continue;
}
PsiElement range = getMethodRange(method);
LineMarkerInfo info = createSuperMethodLineMarkerInfo(range, AllIcons.Gutter.ImplementingMethod, Pass.UPDATE_OVERRIDEN_MARKERS);
ArrowUpLineMarkerInfo upInfo = new ArrowUpLineMarkerInfo(range, AllIcons.Gutter.ImplementingMethod, MarkerType.SIBLING_OVERRIDING_METHOD,
Pass.UPDATE_OVERRIDEN_MARKERS);
LineMarkerInfo info = NavigateAction.setNavigateAction(upInfo, "Go to super method", IdeActions.ACTION_GOTO_SUPER);
result.add(info);
}
}
@@ -33,8 +33,10 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.FindSuperElementsHelper;
import com.intellij.psi.presentation.java.ClassPresentationUtil;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.PsiElementProcessorAdapter;
import com.intellij.psi.search.SearchScope;
@@ -54,6 +56,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Comparator;
@@ -119,6 +122,24 @@ public class MarkerType {
navigateToOverridingMethod(e, method, method != element.getParent());
}
});
static final MarkerType SIBLING_OVERRIDING_METHOD = new MarkerType("SIBLING_OVERRIDING_METHOD", new NullableFunction<PsiElement, String>() {
@Override
public String fun(PsiElement element) {
PsiElement parent = getParentMethod(element);
if (!(parent instanceof PsiMethod)) return null;
PsiMethod method = (PsiMethod)parent;
return calculateOverridingSiblingMethodTooltip(method);
}
}, new LineMarkerNavigator() {
@Override
public void browse(MouseEvent e, PsiElement element) {
PsiElement parent = getParentMethod(element);
if (!(parent instanceof PsiMethod)) return;
PsiMethod method = (PsiMethod)parent;
navigateToSiblingOverridingMethod(e, method);
}
});
@Nullable
private static String calculateOverridingMethodTooltip(@NotNull PsiMethod method, boolean acceptSelf) {
@@ -139,6 +160,22 @@ public class MarkerType {
}
return composeText(superMethods, "", DaemonBundle.message(key), IdeActions.ACTION_GOTO_SUPER);
}
@Nullable
private static String calculateOverridingSiblingMethodTooltip(@NotNull PsiMethod method) {
Pair<PsiMethod, PsiClass> pair =
FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, FindSuperElementsHelper.createSubClassCache());
if (pair == null) return null;
PsiMethod superMethod = pair.getFirst();
PsiClass subClass = pair.getSecond();
boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT);
boolean isSuperAbstract = superMethod.hasModifierProperty(PsiModifier.ABSTRACT);
String postfix = MessageFormat.format(" via sub-class <a href=\"#javaClass/{0}\">{0}</a>", ClassPresentationUtil.getNameForClass(subClass, false));
@NonNls String pattern = DaemonBundle.message(isSuperAbstract && !isAbstract ?
"method.implements" :
"method.overrides") + postfix;
return composeText(new PsiElement[]{superMethod}, "", pattern, IdeActions.ACTION_GOTO_SUPER);
}
@NotNull
private static String composeText(@NotNull PsiElement[] methods, @NotNull String start, @NotNull String pattern, @NotNull String actionId) {
@@ -159,6 +196,14 @@ public class MarkerType {
DaemonBundle.message("navigation.findUsages.title.super.method", method.getName()),
new MethodCellRenderer(showMethodNames));
}
private static void navigateToSiblingOverridingMethod(MouseEvent e, @NotNull PsiMethod method) {
PsiMethod superMethod = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method);
if (superMethod == null) return;
PsiElementListNavigator.openTargets(e, new NavigatablePsiElement[]{superMethod},
DaemonBundle.message("navigation.title.super.method", method.getName()),
DaemonBundle.message("navigation.findUsages.title.super.method", method.getName()),
new MethodCellRenderer(false));
}
@NotNull
private static PsiMethod[] composeSuperMethods(@NotNull PsiMethod method, boolean acceptSelf) {
@@ -702,9 +702,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
ASTNode child = node.getFirstChildNode();
while (child != null) {
if (!FormatterUtil.containsWhiteSpacesOnly(child)) {
if (child.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION || child.getElementType() ==
JavaElementType
.REFERENCE_EXPRESSION) {
IElementType type = child.getElementType();
if (type == JavaElementType.METHOD_CALL_EXPRESSION ||
type == JavaElementType.REFERENCE_EXPRESSION) {
collectNodes(nodes, child);
}
else {
@@ -861,10 +861,15 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
@NotNull final List<Block> result,
@NotNull ASTNode child,
@NotNull final WrappingStrategy wrappingStrategy,
final boolean doAlign) {
final Indent externalIndent = Indent.getNoneIndent();
final Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS);
final Indent internalIndentEnforcedToChildren = Indent.getIndent(Indent.Type.CONTINUATION, myIndentSettings.USE_RELATIVE_INDENTS, true);
final boolean doAlign)
{
Indent externalIndent = Indent.getNoneIndent();
Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS);
if (isInsideMethodCallParenthesis(child)) {
internalIndent = Indent.getSmartIndent(Indent.Type.CONTINUATION);
}
AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), JavaTokenType.COMMA);
setChildIndent(internalIndent);
setChildAlignment(alignmentStrategy.getAlignment(null));
@@ -889,7 +894,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
ASTNode prev = child;
boolean afterAnonymousClass = false;
final boolean enforceIndent = shouldEnforceIndentToChildren();
while (child != null) {
isAfterIncomplete = isAfterIncomplete || child.getElementType() == TokenType.ERROR_ELEMENT ||
child.getElementType() == JavaElementType.EMPTY_EXPRESSION;
@@ -898,18 +902,17 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
result.add(createJavaBlock(child, mySettings, myJavaSettings, externalIndent, null, bracketAlignment));
}
else if (child.getElementType() == to) {
result.add(createJavaBlock(child, mySettings, myJavaSettings,
isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent,
null,
isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment)
);
Block block = createJavaBlock(child, mySettings, myJavaSettings,
isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent,
null,
isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment);
result.add(block);
return child;
}
else {
final IElementType elementType = child.getElementType();
Indent indentToUse = enforceIndent ? internalIndentEnforcedToChildren : internalIndent;
AlignmentStrategy alignmentStrategyToUse = canUseAnonymousClassAlignment(child) ? anonymousClassStrategy : alignmentStrategy;
processChild(result, child, alignmentStrategyToUse.getAlignment(elementType), wrappingStrategy.getWrap(elementType), indentToUse);
processChild(result, child, alignmentStrategyToUse.getAlignment(elementType), wrappingStrategy.getWrap(elementType), internalIndent);
if (to == null) {//process only one statement
return child;
}
@@ -926,6 +929,15 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return prev;
}
private boolean isInsideMethodCallParenthesis(ASTNode child) {
ASTNode currentPredecessor = child.getTreeParent();
if (currentPredecessor != null) {
currentPredecessor = currentPredecessor.getTreeParent();
return currentPredecessor != null && currentPredecessor.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION;
}
return false;
}
private static boolean canUseAnonymousClassAlignment(@NotNull ASTNode child) {
// The general idea is to handle situations like below:
// test(new Runnable() {
@@ -967,19 +979,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return true;
}
private boolean shouldEnforceIndentToChildren() {
if (myNode.getElementType() != JavaElementType.EXPRESSION_LIST) {
return false;
}
ASTNode parent = myNode.getTreeParent();
if (parent == null || parent.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) {
return false;
}
PsiExpression[] arguments = ((PsiExpressionList)myNode.getPsi()).getExpressions();
return JavaFormatterUtil.hasMultilineArguments(arguments) && JavaFormatterUtil.isMultilineExceptArguments(arguments);
}
private static boolean isAnonymousClass(@Nullable ASTNode node) {
if (node == null || node.getElementType() != JavaElementType.NEW_EXPRESSION) {
return false;
@@ -75,8 +75,10 @@ class ChainMethodCallsBlockBuilder {
for (int i = 0; i < methodCall.size(); i++) {
ChainedCallChunk currentCallChunk = methodCall.get(i);
if (isMethodCall(currentCallChunk)) {
if (myWrap == null) myWrap = createCallChunkWrap(i, methodCall);
if (myChainedCallsAlignment == null) myChainedCallsAlignment = createCallChunkAlignment(i, methodCall);
if (myWrap == null)
myWrap = createCallChunkWrap(i, methodCall);
if (myChainedCallsAlignment == null)
myChainedCallsAlignment = createCallChunkAlignment(i, methodCall);
}
else {
myWrap = null;
@@ -137,7 +139,7 @@ class ChainMethodCallsBlockBuilder {
private boolean isMethodCall(@NotNull ChainedCallChunk callChunk) {
List<ASTNode> nodes = callChunk.nodes;
return !nodes.isEmpty() && nodes.get(nodes.size() - 1).getElementType() == JavaElementType.EXPRESSION_LIST;
return nodes.size() >= 3 && nodes.get(2).getElementType() == JavaElementType.EXPRESSION_LIST;
}
}
@@ -96,7 +96,7 @@ public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase {
assertSame(MarkerType.OVERRIDDEN_METHOD.getNavigationHandler(), iMarker.getNavigationHandler());
LineMarkerInfo aMarker = findMarkerWithElement(markers, aRun.getNameIdentifier());
assertSame(MarkerType.OVERRIDING_METHOD.getNavigationHandler(), aMarker.getNavigationHandler());
assertSame(MarkerType.SIBLING_OVERRIDING_METHOD.getNavigationHandler(), aMarker.getNavigationHandler());
}
private static LineMarkerInfo findMarkerWithElement(List<LineMarkerInfo> markers, PsiElement psiMethod) {
@@ -48,7 +48,42 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
" .foo();"
);
}
public void testChainedMethodWithComments() throws Exception {
getSettings().ALIGN_MULTILINE_CHAINED_METHODS = true;
doMethodTest("AAAAA.b()\n" +
".c() // comment after line\n" +
".d()\n" +
".e();",
"AAAAA.b()\n" +
" .c() // comment after line\n" +
" .d()\n" +
" .e();");
}
public void testChainedMethodWithBlockComment() {
getSettings().ALIGN_MULTILINE_CHAINED_METHODS = true;
doTextTest("class X {\n" +
" public void test() {\n" +
" AAAAAA.b()\n" +
".c()\n" +
".d()\n" +
" /* simple block comment */\n" +
".e();\n" +
" }\n" +
"}",
"class X {\n" +
" public void test() {\n" +
" AAAAAA.b()\n" +
" .c()\n" +
" .d()\n" +
" /* simple block comment */\n" +
" .e();\n" +
" }\n" +
"}");
}
public void testMultipleMethodAnnotationsCommentedInTheMiddle() throws Exception {
getSettings().BLANK_LINES_AFTER_CLASS_HEADER = 1;
getSettings().getRootSettings().getIndentOptions(StdFileTypes.JAVA).INDENT_SIZE = 4;
@@ -256,7 +291,7 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
"}"
);
}
public void testAnnotatedAndNonAnnotatedFieldsInColumnsAlignment() {
// Inspired by IDEA-60237
@@ -281,10 +316,10 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
"}"
);
}
public void testAlignThrowsKeyword() throws Exception {
// Inspired by IDEA-63820
getSettings().ALIGN_THROWS_KEYWORD = true;
doClassTest(
"public void test()\n" +
@@ -0,0 +1,106 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.formatter.java;
public class JavaFormatterMultilineMethodCallParamsTest extends AbstractJavaFormatterTest {
public void testChainedMethodInsideCall() {
doMethodTest(
"call(new StringBuilder()\n" +
".append(\"aaa\")\n" +
".append(\"bbbb\"));",
"call(new StringBuilder()\n" +
" .append(\"aaa\")\n" +
" .append(\"bbbb\"));"
);
}
public void IGNORED_testChainedMethodInsideCall_WithRParenOnNewLine() {
doMethodTest(
"call(new StringBuilder()\n" +
".append(\"aaa\")\n" +
".append(\"bbbb\")\n" +
");",
"call(new StringBuilder()\n" +
" .append(\"aaa\")\n" +
" .append(\"bbbb\")\n" +
");"
);
}
public void testChainedMethodInsideCall_Shifted() {
doMethodTest(
"call(new StringBuilder()\n" +
".append(\"aaa\")\n" +
".append(\"bbbb\"),\n" +
"\"aaaa\");",
"call(new StringBuilder()\n" +
" .append(\"aaa\")\n" +
" .append(\"bbbb\"),\n" +
" \"aaaa\");"
);
}
public void testChainedMethodInsideCall_Shifted_WithRParentOnNewLine() {
doMethodTest(
"call(new StringBuilder()\n" +
".append(\"aaa\")\n" +
".append(\"bbbb\"),\n" +
"\"aaaa\"\n" +
");",
"call(new StringBuilder()\n" +
" .append(\"aaa\")\n" +
" .append(\"bbbb\"),\n" +
" \"aaaa\"\n" +
");"
);
}
public void testAnonClassAsParameter() {
doMethodTest(
"call(new Runnable() {\n" +
"@Override\n" +
"public void run() {\n" +
"}\n" +
"});",
"call(new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" }\n" +
"});"
);
}
public void testAnonClassWithRParent_OnNextLine() {
doMethodTest(
"foo(new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" }\n" +
"}\n" +
");\n",
"foo(new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" }\n" +
" }\n" +
");\n"
);
}
}
@@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util
import com.intellij.openapi.util.*
import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
import com.intellij.util.ArrayUtilRt
@@ -240,15 +241,14 @@ abstract class ComponentStoreImpl : IComponentStore {
val defaultState = if (stateSpec.defaultStateAsResource) getDefaultState(component, name, stateClass) else null
val storageSpecs = getStorageSpecs(component, stateSpec, StateStorageOperation.READ)
val stateStorageChooser = component as? StateStorageChooserEx
val storageChooser = component as? StateStorageChooserEx
for (storageSpec in storageSpecs) {
val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ)
if (resolution === Resolution.SKIP) {
if (storageChooser?.getResolution(storageSpec, StateStorageOperation.READ) == Resolution.SKIP) {
continue
}
val storage = storageManager.getStateStorage(storageSpec)
var stateGetter = (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass)
var stateGetter = if (isUseLoadedStateAsExisting(storageSpec) && Registry.`is`("use.loaded.state.as.existing", false)) (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) else null
var state = if (stateGetter == null) storage.getState(component, name, stateClass, defaultState, reloadData) else stateGetter.getState(defaultState)
if (state == null) {
if (changedStorages != null && changedStorages.contains(storage)) {
@@ -276,6 +276,8 @@ abstract class ComponentStoreImpl : IComponentStore {
return name
}
protected open fun isUseLoadedStateAsExisting(storageSpec: Storage): Boolean = true
protected open fun getPathMacroManagerForDefaults(): PathMacroManager? = null
private fun <T : Any> getDefaultState(component: Any, componentName: String, stateClass: Class<T>): T? {
@@ -62,7 +62,7 @@ open class DirectoryBasedStorage(private val myPathMacroSubstitutor: TrackingPat
}
}
override fun getState(storageData: Map<String, StateMap>, component: Any?, componentName: String) = getCompositeStateAndArchive(storageData, componentName, mySplitter)
override fun getSerializedState(storageData: Map<String, StateMap>, component: Any?, componentName: String, archive: Boolean) = getCompositeStateAndArchive(storageData, componentName, mySplitter)
override fun loadData(): MutableMap<String, StateMap> {
return fromMap(DirectoryStorageUtil.loadFrom(getVirtualFile(), myPathMacroSubstitutor))
@@ -174,7 +174,7 @@ open class DirectoryBasedStorage(private val myPathMacroSubstitutor: TrackingPat
writeFile(null, this, file, storeElement, LineSeparator.fromString(if (file.exists()) loadFile(file).second else SystemProperties.getLineSeparator()), false)
}
catch (e: IOException) {
StateStorageBase.LOG.error(e)
LOG.error(e)
}
finally {
if (element != null) {
@@ -288,6 +288,8 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM
}
override fun selectDefaultStorages(storages: Array<Storage>, operation: StateStorageOperation) = selectDefaultStorages(storages, operation, scheme)
override fun isUseLoadedStateAsExisting(storageSpec: Storage) = storageSpec.file != StoragePathMacros.WORKSPACE_FILE
}
fun selectDefaultStorages(storages: Array<Storage>, operation: StateStorageOperation, scheme: StorageScheme): Array<Storage> {
@@ -122,8 +122,6 @@ class StateMap private constructor(private val names: Array<String>, private val
fun isEmpty() = names.isEmpty()
fun getState(key: String) = get(key) as? Element
fun hasState(key: String) = get(key) is Element
public fun hasStates(): Boolean {
@@ -152,14 +150,19 @@ class StateMap private constructor(private val names: Array<String>, private val
}
}
public fun getStateAndArchive(key: String): Element? {
fun getStateAndArchive(key: String) = getState(key, true)
fun getState(key: String, archive: Boolean = false): Element? {
val index = Arrays.binarySearch(names, key)
if (index < 0) {
return null
}
val state = states.get(index) as? Element ?: return null
return if (states.compareAndSet(index, state, archiveState(state))) state else getStateAndArchive(key)
if (!archive) {
return state
}
return if (states.compareAndSet(index, state, archiveState(state))) state else getState(key, true)
}
public fun archive(key: String, state: Element?) {
@@ -28,22 +28,23 @@ abstract class StorageBaseEx<T : Any> : StateStorageBase<T>() {
abstract fun archiveState(storageData: T, componentName: String, serializedState: Element?)
}
class StateGetter<S : Any, T : Any>(private val component: PersistentStateComponent<S>, private val componentName: String, private val storageData: T, private val stateClass: Class<S>, private val storage: StorageBaseEx<T>) {
class StateGetter<S : Any, T : Any>(private val component: PersistentStateComponent<S>,
private val componentName: String,
private val storageData: T,
private val stateClass: Class<S>,
private val storage: StorageBaseEx<T>) {
var serializedState: Element? = null
fun getState(mergeInto: S? = null): S? {
LOG.assertTrue(serializedState == null)
serializedState = storage.getState(storageData, component, componentName)
serializedState = storage.getSerializedState(storageData, component, componentName, false)
if (serializedState != null) {
//System.out.println("open $componentName to read state, ${hashCode()} $storage, ${Thread.currentThread()}")
}
return storage.deserializeState(serializedState, stateClass, mergeInto)
}
/**
* nullable - because PersistentStateComponent can return nullable state
*/
fun close() {
if (serializedState == null) {
return
@@ -37,7 +37,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S
protected abstract fun loadLocalData(): Element?
override final fun getState(storageData: StateMap, component: Any?, componentName: String) = storageData.getState(componentName)
override final fun getSerializedState(storageData: StateMap, component: Any?, componentName: String, archive: Boolean) = storageData.getState(componentName, archive)
override fun archiveState(storageData: StateMap, componentName: String, serializedState: Element?) {
storageData.archive(componentName, serializedState)
@@ -110,7 +110,7 @@ class ApplicationStoreTest {
}
@State(name = "A", storages = arrayOf(Storage(file = "a.xml")))
private class A : PersistentStateComponent<Element> {
private open class A : PersistentStateComponent<Element> {
data class State(@Attribute var foo: String = "", @Attribute var bar: String = "")
var state = State()
@@ -144,6 +144,24 @@ class ApplicationStoreTest {
assertThat(file).hasContent("<application>\n <component name=\"A\" foo=\"1\" bar=\"2\" />\n</application>")
}
@Test fun `do not apply to workspace storage - do not save if only format is changed`() {
@State(name = "A", storages = arrayOf(Storage(file = StoragePathMacros.WORKSPACE_FILE)))
class AWorkspace : A()
val oldContent = "<application><component name=\"A\" foo=\"old\" deprecated=\"old\"/></application>"
val file = writeConfig("workspace.xml", oldContent)
val oldModificationTime = file.getLastModifiedTime()
testAppConfig.refreshVfs()
val component = AWorkspace()
componentStore.initComponent(component, false)
assertThat(component.state).isEqualTo(A.State("old"))
saveStore()
assertThat(file).hasContent("<application>\n <component name=\"A\" foo=\"old\" />\n</application>")
}
private fun saveStore() {
runInEdtAndWait { componentStore.save(SmartList()) }
}
@@ -188,7 +206,10 @@ class ApplicationStoreTest {
override fun setPath(path: String) {
storageManager.addMacro(StoragePathMacros.APP_CONFIG, path)
storageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, "$path/workspace.xml")
}
override fun isUseLoadedStateAsExisting(storageSpec: Storage) = storageSpec.file != StoragePathMacros.WORKSPACE_FILE
}
abstract class Foo {
@@ -24,7 +24,7 @@ import org.junit.Test
class XmlElementStorageTest {
@Test fun testGetStateSucceeded() {
val storage = MyXmlElementStorage(tag("root", tag("component", attr("name", "test"), tag("foo"))))
val state = storage.getState(this, "test", javaClass<Element>(), null, false)
val state = storage.getState(this, "test", javaClass<Element>())
assertThat(state).isNotNull()
assertThat(state!!.getName()).isEqualTo("component")
assertThat(state.getChild("foo")).isNotNull()
@@ -32,7 +32,7 @@ class XmlElementStorageTest {
@Test fun `get state not succeeded`() {
val storage = MyXmlElementStorage(tag("root"))
val state = storage.getState(this, "test", javaClass<Element>(), null, false)
val state = storage.getState(this, "test", javaClass<Element>())
assertThat(state).isNull()
}
@@ -360,24 +360,28 @@ public class LexerEditorHighlighter implements EditorHighlighter, PrioritizedDoc
// Called to determine visual attributes of inserted character prior to starting a write action.
// TODO Should be removed when we implement typing without starting write actions.
public TextAttributes getAttributes(DocumentImpl document, int offset, char c) {
final int segmentIndex;
try {
segmentIndex = mySegments.findSegmentIndex(offset) - 2;
}
catch (IndexOutOfBoundsException ex) {
throw new IndexOutOfBoundsException(ex.getMessage() + " Lexer: " + myLexer);
}
int startIndex = Math.max(0, segmentIndex);
int startOffset = 0;
int data;
do {
data = mySegments.getSegmentData(startIndex);
if (isInitialState(data)|| startIndex == 0) break;
startIndex--;
}
while (true);
if (mySegments.getSegmentCount() > 0) {
final int segmentIndex;
try {
segmentIndex = mySegments.findSegmentIndex(offset) - 2;
}
catch (IndexOutOfBoundsException ex) {
throw new IndexOutOfBoundsException(ex.getMessage() + " Lexer: " + myLexer);
}
int startIndex = Math.max(0, segmentIndex);
int startOffset = mySegments.getSegmentStart(startIndex);
int data;
do {
data = mySegments.getSegmentData(startIndex);
if (isInitialState(data)|| startIndex == 0) break;
startIndex--;
}
while (true);
startOffset = mySegments.getSegmentStart(startIndex);
}
ImmutableText newText = document.getImmutableText().insert(offset, Character.toString(c));
@@ -269,6 +269,10 @@ public abstract class Indent {
return myFactory.getIndent(type, spaces, relativeToDirectParent, enforceIndentToChildren);
}
public static Indent getSmartIndent(Type type) {
return myFactory.getSmartIndent(type);
}
public static class Type {
private final String myName;
@@ -34,4 +34,5 @@ interface IndentFactory {
Indent getSpaceIndent(final int spaces, boolean relativeToDirectParent);
Indent getIndent(@NotNull Indent.Type type, boolean relativeToDirectParent, boolean enforceIndentToChildren);
Indent getIndent(@NotNull Indent.Type type, int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren);
Indent getSmartIndent(@NotNull Indent.Type type);
}
@@ -61,8 +61,9 @@ public class CommonCodeStyleSettingsManager implements JDOMExternalizable {
public CommonCodeStyleSettings getCommonSettings(@Nullable Language lang) {
Map<Language, CommonCodeStyleSettings> commonSettingsMap = getCommonSettingsMap();
CommonCodeStyleSettings settings = commonSettingsMap.get(lang);
if (settings == null && lang != null) {
settings = commonSettingsMap.get(lang.getBaseLanguage());
while (settings == null && lang != null) {
lang = lang.getBaseLanguage();
settings = commonSettingsMap.get(lang);
}
if (settings != null) {
return settings;
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2015 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.formatting;
public class ExpandableIndent extends IndentImpl {
private boolean myEnforceIndent;
public ExpandableIndent(Type type) {
super(type, false, 0, false, true);
myEnforceIndent = false;
}
@Override
public boolean isEnforceIndentToChildren() {
return myEnforceIndent;
}
void setEnforceIndent(boolean value) {
myEnforceIndent = value;
}
}
@@ -34,6 +34,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
@@ -158,6 +159,7 @@ public class FormatProcessor {
@NotNull
private State myCurrentState;
private MultiMap<ExpandableIndent, AbstractBlockWrapper> myExpandableIndents;
public FormatProcessor(final FormattingDocumentModel docModel,
Block rootBlock,
@@ -248,7 +250,11 @@ public class FormatProcessor {
public void format(FormattingModel model, boolean sequentially) {
if (sequentially) {
AdjustWhiteSpacesState adjustState = new AdjustWhiteSpacesState();
adjustState.setNext(new ApplyChangesState(model));
ExpandChildrenIndent expandChildrenIndent = new ExpandChildrenIndent();
ApplyChangesState applyChangesState = new ApplyChangesState(model);
expandChildrenIndent.setNext(applyChangesState);
adjustState.setNext(expandChildrenIndent);
myCurrentState.setNext(adjustState);
}
else {
@@ -284,7 +290,9 @@ public class FormatProcessor {
@SuppressWarnings({"WhileLoopSpinsOnField"})
public void formatWithoutRealModifications(boolean sequentially) {
myCurrentState.setNext(new AdjustWhiteSpacesState());
AdjustWhiteSpacesState adjustSpace = new AdjustWhiteSpacesState();
adjustSpace.setNext(new ExpandChildrenIndent());
myCurrentState.setNext(adjustSpace);
if (sequentially) {
return;
@@ -1357,6 +1365,8 @@ public class FormatProcessor {
root, model, affectedRanges, mySettings, myDefaultIndentOption, interestingOffset, myProgressCallback
);
myWrapper.setCollectAlignmentsInsideFormattingRange(myReformatContext);
myExpandableIndents = myWrapper.getExpandableIndentsBlocks();
}
@Override
@@ -1526,24 +1536,24 @@ public class FormatProcessor {
}
}
}
private static class CaretOffsetUpdater {
private final Map<Editor, Integer> myCaretOffsets = new HashMap<Editor, Integer>();
private CaretOffsetUpdater(@NotNull Document document) {
Editor[] editors = EditorFactory.getInstance().getEditors(document);
for (Editor editor : editors) {
myCaretOffsets.put(editor, editor.getCaretModel().getOffset());
}
}
private void update(@NotNull List<? extends TextChange> changes) {
BulkChangesMerger merger = BulkChangesMerger.INSTANCE;
for (Map.Entry<Editor, Integer> entry : myCaretOffsets.entrySet()) {
entry.setValue(merger.updateOffset(entry.getValue(), changes));
}
}
private void restoreCaretLocations() {
for (Map.Entry<Editor, Integer> entry : myCaretOffsets.entrySet()) {
entry.getKey().getCaretModel().moveToOffset(entry.getValue());
@@ -1580,4 +1590,80 @@ public class FormatProcessor {
myInterestingOffset = interestingOffset;
}
}
private class ExpandChildrenIndent extends State {
private Iterator<ExpandableIndent> myIterator;
public ExpandChildrenIndent() {
super(FormattingStateId.EXPANDING_CHILDREN_INDENTS);
}
@Override
protected void doIteration() {
if (myIterator == null) {
myIterator = myExpandableIndents.keySet().iterator();
}
if (!myIterator.hasNext()) {
setDone(true);
return;
}
final ExpandableIndent indent = myIterator.next();
Collection<AbstractBlockWrapper> blocksToExpandIndent = myExpandableIndents.get(indent);
if (shouldExpand(blocksToExpandIndent)) {
for (AbstractBlockWrapper block : blocksToExpandIndent) {
indent.setEnforceIndent(true);
reindentNewLineChildren(block);
indent.setEnforceIndent(false);
}
}
}
private boolean shouldExpand(Collection<AbstractBlockWrapper> blocksToExpandIndent) {
AbstractBlockWrapper last = null;
for (AbstractBlockWrapper block : blocksToExpandIndent) {
if (block.getWhiteSpace().containsLineFeeds()) {
return true;
}
last = block;
}
if (last != null) {
AbstractBlockWrapper prev = getPreviousBlock(last);
return prev != null && prev.getWhiteSpace().containsLineFeeds();
}
return false;
}
private AbstractBlockWrapper getPreviousBlock(AbstractBlockWrapper block) {
List<AbstractBlockWrapper> children = block.getParent().getChildren();
int nextBlockIndex = children.indexOf(block) + 1;
if (nextBlockIndex < children.size()) {
return children.get(nextBlockIndex);
}
return null;
}
private void reindentNewLineChildren(final @NotNull AbstractBlockWrapper block) {
if (block instanceof LeafBlockWrapper) {
WhiteSpace space = block.getWhiteSpace();
if (space.containsLineFeeds()) {
myCurrentBlock = (LeafBlockWrapper)block;
adjustIndent();
}
}
else if (block instanceof CompositeBlockWrapper) {
List<AbstractBlockWrapper> children = ((CompositeBlockWrapper)block).getChildren();
for (AbstractBlockWrapper childBlock : children) {
reindentNewLineChildren(childBlock);
}
}
}
@Override
protected void prepare() {
}
}
}
@@ -818,6 +818,11 @@ public class FormatterImpl extends FormatterEx
return getIndent(type, 0, relativeToDirectParent, enforceIndentToChildren);
}
@Override
public Indent getSmartIndent(@NotNull Indent.Type type) {
return new ExpandableIndent(type);
}
@Override
public Indent getIndent(@NotNull Indent.Type type, int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren) {
return new IndentImpl(type, false, spaces, relativeToDirectParent, enforceIndentToChildren);
@@ -46,6 +46,8 @@ public enum FormattingStateId {
*/
PROCESSING_BLOCKS(1),
EXPANDING_CHILDREN_INDENTS(5),
/**
* This element corresponds to formatting phase when all {@link AbstractBlockWrapper wrapped code blocks} are processed and it's
* time to apply the changes to the underlying document.
@@ -24,21 +24,39 @@ public class IndentInfo {
private final int mySpaces;
private final int myIndentSpaces;
private final int myLineFeeds;
private final int myHiddenSpaces;
private final int myLineFeeds;
/** @see WhiteSpace#setForceSkipTabulationsUsage(boolean) */
private final boolean myForceSkipTabulationsUsage;
private boolean myIndentEmptyLines; // Additional indent on empty lines (before the end of code block)
public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces) {
this(lineFeeds, indentSpaces, spaces, false);
this(lineFeeds, indentSpaces, spaces, 0, false);
}
public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces, final boolean forceSkipTabulationsUsage) {
public IndentInfo(final int lineFeeds,
final int indentSpaces,
final int spaces,
final int hiddenSpaces)
{
this(lineFeeds, indentSpaces, spaces, hiddenSpaces, false);
}
public IndentInfo(final int lineFeeds,
final int indentSpaces,
final int spaces,
final boolean forceSkipTabulationsUsage)
{
this(lineFeeds, indentSpaces, spaces, 0, forceSkipTabulationsUsage);
}
public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces, final int hiddenSpaces, final boolean forceSkipTabulationsUsage) {
mySpaces = spaces;
myIndentSpaces = indentSpaces;
myLineFeeds = lineFeeds;
myForceSkipTabulationsUsage = forceSkipTabulationsUsage;
myHiddenSpaces = hiddenSpaces;
}
public int getSpaces() {
@@ -29,6 +29,8 @@ import com.intellij.psi.formatter.FormattingDocumentModelImpl;
import com.intellij.psi.formatter.ReadOnlyBlockInformationProvider;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.LinkedMultiMap;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.Stack;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
@@ -74,6 +76,8 @@ class InitialInfoBuilder {
private Set<Alignment> myAlignmentsInsideRangeToModify = ContainerUtil.newHashSet();
private boolean myCollectAlignmentsInsideFormattingRange = false;
private MultiMap<ExpandableIndent, AbstractBlockWrapper> myBlocksToForceChildrenIndent = new LinkedMultiMap<ExpandableIndent, AbstractBlockWrapper>();
private InitialInfoBuilder(final Block rootBlock,
final FormattingDocumentModel model,
@Nullable final FormatTextRanges affectedRanges,
@@ -285,6 +289,10 @@ class InitialInfoBuilder {
return wrappedRootBlock;
}
public MultiMap<ExpandableIndent, AbstractBlockWrapper> getExpandableIndentsBlocks() {
return myBlocksToForceChildrenIndent;
}
private void doIteration(@NotNull State state) {
List<Block> subBlocks = state.parentBlock.getSubBlocks();
final int subBlocksCount = subBlocks.size();
@@ -303,6 +311,7 @@ class InitialInfoBuilder {
final AbstractBlockWrapper wrapper = buildFrom(
block, childBlockIndex, state.wrappedBlock, state.parentBlockWrap, state.parentBlock, childBlockIsRightBlock
);
registerExpandableIndents(block, wrapper);
if (wrapper.getIndent() == null) {
wrapper.setIndent((IndentImpl)block.getIndent());
@@ -321,7 +330,14 @@ class InitialInfoBuilder {
}
}
}
private void registerExpandableIndents(@NotNull Block block, @NotNull AbstractBlockWrapper wrapper) {
if (block.getIndent() instanceof ExpandableIndent) {
ExpandableIndent indent = (ExpandableIndent)block.getIndent();
myBlocksToForceChildrenIndent.putValue(indent, wrapper);
}
}
private void setDefaultIndents(final List<AbstractBlockWrapper> list) {
if (!list.isEmpty()) {
for (AbstractBlockWrapper wrapper : list) {
@@ -25,6 +25,7 @@ import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.components.impl.stores.StateStorageBase;
import com.intellij.openapi.components.impl.stores.StateStorageManager;
import com.intellij.openapi.components.impl.stores.StorageManagerListener;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootModel;
@@ -55,6 +56,8 @@ import java.util.Set;
// Boolean - false as not loaded, true as loaded
public class ClasspathStorage extends StateStorageBase<Boolean> {
private static final Logger LOG = Logger.getInstance(ClasspathStorage.class);
@NonNls public static final String SPECIAL_STORAGE = "special";
private final ClasspathStorageProvider.ClasspathConverter myConverter;
@@ -135,7 +138,7 @@ public class ClasspathStorage extends StateStorageBase<Boolean> {
@Nullable
@Override
public Element getState(@NotNull Boolean storageData, Object component, @NotNull String componentName) {
public Element getSerializedState(@NotNull Boolean storageData, Object component, @NotNull String componentName, boolean archive) {
if (storageData) {
return null;
}
@@ -29,10 +29,10 @@ import com.intellij.openapi.fileTypes.FileTypeListener;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter;
@@ -60,6 +60,30 @@ public class PsiVFSListener extends VirtualFileAdapter {
private final Project myProject;
private boolean myReportedUnloadedPsiChange;
static {
ApplicationManager.getApplication().getMessageBus().connect().subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
@Override
public void before(@NotNull List<? extends VFileEvent> events) {
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
PsiVFSListener listener = project.getComponent(PsiVFSListener.class);
assert listener != null;
new BulkVirtualFileListenerAdapter(listener).before(events);
}
}
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
PsiVFSListener listener = project.getComponent(PsiVFSListener.class);
assert listener != null;
listener.myReportedUnloadedPsiChange = false;
new BulkVirtualFileListenerAdapter(listener).after(events);
listener.myReportedUnloadedPsiChange = false;
}
}
});
}
public PsiVFSListener(Project project) {
myProject = project;
myFileTypeManager = FileTypeManager.getInstance();
@@ -72,20 +96,6 @@ public class PsiVFSListener extends VirtualFileAdapter {
StartupManager.getInstance(project).registerPreStartupActivity(new Runnable() {
@Override
public void run() {
final BulkVirtualFileListenerAdapter adapter = new BulkVirtualFileListenerAdapter(PsiVFSListener.this);
myConnection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
@Override
public void before(@NotNull List<? extends VFileEvent> events) {
adapter.before(events);
}
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
myReportedUnloadedPsiChange = false;
adapter.after(events);
myReportedUnloadedPsiChange = false;
}
});
myConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyModuleRootListener());
myConnection.subscribe(FileTypeManager.TOPIC, new FileTypeListener.Adapter() {
@Override
@@ -595,11 +605,6 @@ public class PsiVFSListener extends VirtualFileAdapter {
true, false);
}
// When file is renamed so that extension changes then language dialect might change and thus psiFile should be invalidated
private static boolean languageDialectChanged(final PsiFile newPsiFile, String oldFileName) {
return newPsiFile != null && !FileUtilRt.extensionEquals(oldFileName, FileUtilRt.getExtension(newPsiFile.getName()));
}
private class MyModuleRootListener implements ModuleRootListener {
private VirtualFile[] myOldContentRoots = null;
private volatile int depthCounter = 0;
@@ -22,22 +22,26 @@ import java.util.concurrent.atomic.AtomicReference
public abstract class StateStorageBase<T : Any> : StateStorage {
companion object {
protected val LOG: Logger = Logger.getInstance(javaClass<StateStorageBase<Any>>())
private val LOG: Logger = Logger.getInstance(javaClass<StateStorageBase<Any>>())
}
private var mySavingDisabled = false
protected val storageDataRef: AtomicReference<T> = AtomicReference()
override fun <S> getState(component: Any?, componentName: String, stateClass: Class<S>, mergeInto: S?, reload: Boolean): S? {
return deserializeState(getState(getStorageData(reload), component, componentName), stateClass, mergeInto)
override final fun <S> getState(component: Any?, componentName: String, stateClass: Class<S>, mergeInto: S?, reload: Boolean): S? {
return getState(component, componentName, stateClass, true, reload, mergeInto)
}
fun <S : Any> getState(component: Any?, componentName: String, stateClass: Class<S>, archive: Boolean = true, reload: Boolean = false, mergeInto: S? = null): S? {
return deserializeState(getSerializedState(getStorageData(reload), component, componentName, archive), stateClass, mergeInto)
}
open fun <S> deserializeState(serializedState: Element?, stateClass: Class<S>, mergeInto: S?): S? {
return DefaultStateSerializer.deserializeState(serializedState, stateClass, mergeInto)
}
abstract fun getState(storageData: T, component: Any?, componentName: String): Element?
abstract fun getSerializedState(storageData: T, component: Any?, componentName: String, archive: Boolean = true): Element?
protected abstract fun hasState(storageData: T, componentName: String): Boolean
@@ -45,9 +49,7 @@ public abstract class StateStorageBase<T : Any> : StateStorage {
return hasState(getStorageData(reloadData), componentName)
}
public fun getStorageData(): T {
return getStorageData(false)
}
public fun getStorageData(): T = getStorageData(false)
protected fun getStorageData(reload: Boolean): T {
val storageData = storageDataRef.get()
@@ -52,6 +52,8 @@ public abstract class EditorGutterComponentEx extends JComponent implements Edit
public abstract int getLineMarkerAreaOffset();
public abstract int getIconAreaOffset();
public abstract int getLineMarkerFreePaintersAreaOffset();
public abstract int getIconsAreaWidth();
@@ -82,8 +82,9 @@ import java.util.List;
class EditorGutterComponentImpl extends EditorGutterComponentEx implements MouseListener, MouseMotionListener, DataProvider {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.EditorGutterComponentImpl");
private static final int START_ICON_AREA_WIDTH = 15;
private static final int FREE_PAINTERS_AREA_WIDTH = 5;
private static final int GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA = 5;
private static final int FREE_PAINTERS_LEFT_AREA_WIDTH = 8;
private static final int FREE_PAINTERS_RIGHT_AREA_WIDTH = 5;
private static final int GAP_BETWEEN_ICONS_AND_RIGHT_FREE_PAINTERS_AREA = 5;
private static final int GAP_BETWEEN_ICONS = 3;
private static final int GAP_BEFORE_LINE_NUMBERS = 5;
private static final int GAP_AFTER_LINE_NUMBERS = 4;
@@ -97,7 +98,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private final EditorImpl myEditor;
private final FoldingAnchorsOverlayStrategy myAnchorsDisplayStrategy;
private int myLineMarkerAreaWidth = START_ICON_AREA_WIDTH + GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA + FREE_PAINTERS_AREA_WIDTH;
private int myIconsAreaWidth = START_ICON_AREA_WIDTH;
private int myLineNumberAreaWidth = 0;
private int myAdditionalLineNumberAreaWidth = 0;
@@ -116,6 +116,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
@Nullable private ActionGroup myCustomGutterPopupGroup;
private TIntObjectHashMap<Color> myTextFgColors = new TIntObjectHashMap<Color>();
private boolean myPaintBackground = true;
private boolean myLeftFreePaintersAreaShown;
@SuppressWarnings("unchecked")
public EditorGutterComponentImpl(EditorImpl editor) {
@@ -629,14 +630,14 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private void updateSizeInner(boolean onLayout) {
if (!onLayout) {
calcLineNumberAreaWidth();
calcIconAreaWidth();
calcLineMarkerAreaWidth();
calcAnnotationsSize();
}
calcAnnotationExtraSize();
}
private int sizeHash() {
int result = myLineMarkerAreaWidth;
int result = getLineMarkerAreaWidth();
result = 31 * result + myTextAnnotationGuttersSize;
result = 31 * result + myTextAnnotationExtraSize;
result = 31 * result + getLineNumberAreaWidth();
@@ -682,19 +683,27 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
int width = editorLocationX + editorComponent.getWidth();
if (rightMarginX < width && editorLocationX < width - rightMarginX) {
int centeredSize = (width - rightMarginX - editorLocationX) / 2 - (myLineMarkerAreaWidth + getLineNumberAreaWidth());
int centeredSize = (width - rightMarginX - editorLocationX) / 2 - (getLineMarkerAreaWidth() + getLineNumberAreaWidth());
myTextAnnotationExtraSize = Math.max(0, centeredSize - myTextAnnotationGuttersSize);
}
}
private TIntObjectHashMap<List<GutterMark>> myLineToGutterRenderers;
private void calcIconAreaWidth() {
private void calcLineMarkerAreaWidth() {
myLineToGutterRenderers = new TIntObjectHashMap<List<GutterMark>>();
myLeftFreePaintersAreaShown = false;
processRangeHighlighters(0, myEditor.getDocument().getTextLength(), new RangeHighlighterProcessor() {
@Override
public void process(@NotNull RangeHighlighter highlighter) {
LineMarkerRenderer lineMarkerRenderer = highlighter.getLineMarkerRenderer();
if (lineMarkerRenderer instanceof LineMarkerRendererEx &&
((LineMarkerRendererEx)lineMarkerRenderer).getPosition() == LineMarkerRendererEx.Position.LEFT &&
isLineMarkerVisible(highlighter)) {
myLeftFreePaintersAreaShown = true;
}
GutterMark renderer = highlighter.getGutterIconRenderer();
if (renderer == null) {
return;
@@ -734,8 +743,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
return true;
}
});
myLineMarkerAreaWidth = myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA + FREE_PAINTERS_AREA_WIDTH;
}
private boolean isHighlighterVisible(RangeHighlighter highlighter) {
@@ -791,28 +798,30 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
private void paintLineMarkerRenderer(RangeHighlighter highlighter, Graphics g) {
Rectangle rectangle = getLineRendererRectangle(highlighter);
if (rectangle != null) {
final LineMarkerRenderer lineMarkerRenderer = highlighter.getLineMarkerRenderer();
assert lineMarkerRenderer != null;
lineMarkerRenderer.paint(myEditor, g, rectangle);
LineMarkerRenderer lineMarkerRenderer = highlighter.getLineMarkerRenderer();
if (lineMarkerRenderer != null) {
Rectangle rectangle = getLineRendererRectangle(highlighter);
if (rectangle != null) {
lineMarkerRenderer.paint(myEditor, g, rectangle);
}
}
}
@Nullable
private Rectangle getLineRendererRectangle(RangeHighlighter highlighter) {
LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer();
if (renderer == null) return null;
private boolean isLineMarkerVisible(RangeHighlighter highlighter) {
int startOffset = highlighter.getStartOffset();
int endOffset = highlighter.getEndOffset();
FoldRegion startFoldRegion = myEditor.getFoldingModel().getCollapsedRegionAtOffset(startOffset);
FoldRegion endFoldRegion = myEditor.getFoldingModel().getCollapsedRegionAtOffset(endOffset);
if (startFoldRegion != null && endFoldRegion != null && startFoldRegion.equals(endFoldRegion)) {
return null;
}
return startFoldRegion == null || endFoldRegion == null || !startFoldRegion.equals(endFoldRegion);
}
@Nullable
private Rectangle getLineRendererRectangle(RangeHighlighter highlighter) {
if (!isLineMarkerVisible(highlighter)) return null;
int startOffset = highlighter.getStartOffset();
int endOffset = highlighter.getEndOffset();
int startY = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(startOffset)).y;
@@ -825,9 +834,13 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
endY += myEditor.getLineHeight();
}
LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer();
boolean leftPosition = renderer instanceof LineMarkerRendererEx &&
((LineMarkerRendererEx)renderer).getPosition() == LineMarkerRendererEx.Position.LEFT;
int height = endY - startY;
int w = FREE_PAINTERS_AREA_WIDTH;
int x = getLineMarkerFreePaintersAreaOffset() - 1;
int w = leftPosition ? FREE_PAINTERS_LEFT_AREA_WIDTH : FREE_PAINTERS_RIGHT_AREA_WIDTH;
int x = leftPosition ? getLineMarkerAreaOffset() : getLineMarkerFreePaintersAreaOffset() - 1;
return new Rectangle(x, startY, w, height);
}
@@ -845,7 +858,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private void processIconsRow(int line, List<GutterMark> row, LineGutterIconRendererProcessor processor) {
int middleCount = 0;
int middleSize = 0;
int x = getLineMarkerAreaOffset() + 2;
int x = getIconAreaOffset() + 2;
final int y = myEditor.logicalPositionToXY(new LogicalPosition(line, 0)).y;
for (GutterMark r : row) {
@@ -862,9 +875,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
}
final int leftSize = x - getLineMarkerAreaOffset();
final int leftSize = x - getIconAreaOffset();
x = getLineMarkerAreaOffset() + myIconsAreaWidth - 2; // because of 2px LineMarkerRenderers
x = getIconAreaOffset() + myIconsAreaWidth - 2; // because of 2px LineMarkerRenderers
for (GutterMark r : row) {
if (!checkDumbAware(r, myEditor.getProject())) continue;
if (((GutterIconRenderer)r).getAlignment() == GutterIconRenderer.Alignment.RIGHT) {
@@ -875,11 +888,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
}
int rightSize = myIconsAreaWidth + getLineMarkerAreaOffset() - x + 1;
int rightSize = myIconsAreaWidth + getIconAreaOffset() - x + 1;
if (middleCount > 0) {
middleSize -= GAP_BETWEEN_ICONS;
x = getLineMarkerAreaOffset() + leftSize + (myIconsAreaWidth - leftSize - rightSize - middleSize) / 2;
x = getIconAreaOffset() + leftSize + (myIconsAreaWidth - leftSize - rightSize - middleSize) / 2;
for (GutterMark r : row) {
if (!checkDumbAware(r, myEditor.getProject())) continue;
if (((GutterIconRenderer)r).getAlignment() == GutterIconRenderer.Alignment.CENTER) {
@@ -1121,7 +1134,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
public int getLineMarkerAreaWidth() {
return isLineMarkersShown() ? myLineMarkerAreaWidth : 0;
return isLineMarkersShown() ? ((myLeftFreePaintersAreaShown ? FREE_PAINTERS_LEFT_AREA_WIDTH : 0) +
myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_RIGHT_FREE_PAINTERS_AREA + FREE_PAINTERS_RIGHT_AREA_WIDTH) :
0;
}
public void setLineNumberAreaWidthFunction(@NotNull TIntFunction calculator) {
@@ -1200,9 +1215,14 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
return getAnnotationsAreaOffset() + getAnnotationsAreaWidthEx();
}
@Override
public int getIconAreaOffset() {
return getLineMarkerAreaOffset() + (myLeftFreePaintersAreaShown ? FREE_PAINTERS_LEFT_AREA_WIDTH : 0);
}
@Override
public int getLineMarkerFreePaintersAreaOffset() {
return getLineMarkerAreaOffset() + myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA;
return getIconAreaOffset() + myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_RIGHT_FREE_PAINTERS_AREA;
}
@Override
@@ -1466,7 +1486,8 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
processRangeHighlighters(firstVisibleOffset, lastVisibleOffset, new RangeHighlighterProcessor() {
@Override
public void process(@NotNull RangeHighlighter highlighter) {
if (gutterRenderer[0] != null) return;
LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer();
if (renderer == null || gutterRenderer[0] != null) return;
Rectangle rectangle = getLineRendererRectangle(highlighter);
if (rectangle == null) return;
@@ -1477,7 +1498,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
if (startY < e.getY() && e.getY() <= endY) {
final LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer();
if (renderer instanceof ActiveGutterRenderer && ((ActiveGutterRenderer)renderer).canDoAction(e)) {
gutterRenderer[0] = (ActiveGutterRenderer)renderer;
}
@@ -2186,7 +2186,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private boolean canPaintImmediately(char c) {
return myDocument instanceof DocumentImpl &&
myHighlighter instanceof LexerEditorHighlighter &&
myDocument.getTextLength() > 0 &&
!mySelectionModel.hasSelection() &&
areVisualLinesUnique(myCaretModel.getAllCarets()) &&
!isInplaceRenamerActive() &&
@@ -2222,8 +2221,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
TextAttributes attributes = ((LexerEditorHighlighter)myHighlighter).getAttributes((DocumentImpl)myDocument, offset, c);
int fontType = attributes.getFontType();
Font font = fontFor(fontType);
FontInfo fontInfo = EditorUtil.fontForChar(c, attributes.getFontType(), this);
Font font = fontInfo.getFont();
// it's more reliable to query actual font metrics
FontMetrics fontMetrics = getFontMetrics(fontType);
int charWidth = fontMetrics.charWidth(c);
@@ -2318,7 +2319,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
Point point = newArea.getLocation();
int ascent = getAscent();
Font font = fontFor(attributes.getFontType());
// simplified font selection (based on the first character)
FontInfo fontInfo = EditorUtil.fontForChar(newText.charAt(0), attributes.getFontType(), this);
Font font = fontInfo.getFont();
Color color = attributes.getForegroundColor() == null ? getForegroundColor() : attributes.getForegroundColor();
EditorUIUtil.setupAntialiasing(g);
@@ -2350,11 +2354,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
return color == null ? getBackgroundColor() : color;
}
@NotNull
private Font fontFor(int fontType) {
return myScheme.getFont(EditorFontType.values()[fontType]);
}
private static void shift(@NotNull Graphics g, @NotNull Rectangle r, int delta) {
g.copyArea(r.x, r.y, r.width, r.height, delta, 0);
}
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2015 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.openapi.editor.markup;
import com.intellij.openapi.editor.Editor;
import java.awt.*;
public interface LineMarkerRendererEx extends LineMarkerRenderer {
enum Position {LEFT, RIGHT}
/**
* Determines whether line marker should be rendered to the left or to the right of icon area in gutter.
* Corresponding rectangle will be passed to renderer in {@link #paint(Editor, Graphics, Rectangle)} method.
*/
Position getPosition();
}
@@ -30,6 +30,7 @@ progress.reformat.and.optimize.common.command.text=Reformat and Optimize Imports
progress.reformat.stage.wrapping.blocks=Preparing...
progress.reformat.stage.processing.blocks=Calculating changes...
progress.reformat.stage.applying.changes=Storing changes...
progress.reformat.stage.expanding.children.indents=Expanding necessary children indents
process.rearrange.code=Rearranging code...
process.reformat.code=Reformat Code
process.reformat.code.before.commit=Reformat Code Before Commit
@@ -520,4 +521,4 @@ dialog.edit.template.checkbox.xsl.text=XSL Text
highlight.imported.classes.chooser.title=Choose Imported Classes to Highlight
highlight.imported.members.chooser.title=Choose Imported Members to Highlight
javadoc.resolved.value=Resolved value\:
javadoc.error.resolving.url=Couldn''t resolve URL <i>{0}</i> <p>Configuring paths to API docs in <a href="open://Project Settings">project settings</a> might help
javadoc.error.resolving.url=Couldn''t resolve URL <i>{0}</i> <p>Configuring paths to API docs in <a href="open://Project Settings">project settings</a> might help
@@ -652,6 +652,7 @@ testDiscovery.enabled=false
ruby.remote.debugger.supports.catchpoint.removal=true
use.read.action.to.init.service=true
use.loaded.state.as.existing=false
ide.mac.new.color.picker=false
@@ -55,7 +55,7 @@ public class SuperTearDownInFinallyInspection extends BaseInspection {
return;
}
final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiMember.class, PsiLambdaExpression.class);
if (method == null) {
if (method == null || !method.getName().equals("tearDown")) {
return;
}
final PsiClass containingClass = method.getContainingClass();
@@ -1,17 +1,19 @@
class SuperTearDownInFinally extends junit.framework.TestCase {
import junit.framework.TestCase;
class SuperTearDownInFinally extends TestCase {
public void tearDown() throws Exception {
super.<warning descr="'tearDown()' not called from 'finally' block">tearDown</warning>();
System.out.println();
}
}
class NoProblem extends junit.framework.TestCase {
class NoProblem extends TestCase {
public void tearDown() throws Exception {
super.tearDown();
}
}
class CalledInFinally extends junit.framework.TestCase {
class CalledInFinally extends TestCase {
public void tearDown() throws Exception {
try {
@@ -20,4 +22,16 @@ class CalledInFinally extends junit.framework.TestCase {
super.tearDown();
}
}
}
class SomeTest extends TestCase {
@Override
protected void setUp() throws Exception {
try {
super.setUp();
}
catch (Throwable t) {
super.tearDown(); // yellow code
}
}
public void test_something() {}
}
@@ -1,5 +1,17 @@
/*
* Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
* Copyright 2000-2015 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.coverage;
@@ -25,6 +37,7 @@ import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.editor.markup.ActiveGutterRenderer;
import com.intellij.openapi.editor.markup.LineMarkerRendererEx;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SearchableConfigurable;
@@ -57,7 +70,7 @@ import java.util.TreeMap;
/**
* @author ven
*/
public class CoverageLineMarkerRenderer implements ActiveGutterRenderer {
public class CoverageLineMarkerRenderer implements LineMarkerRendererEx, ActiveGutterRenderer {
private static final int THICKNESS = 8;
private final TextAttributesKey myKey;
private final String myClassName;
@@ -97,10 +110,10 @@ public class CoverageLineMarkerRenderer implements ActiveGutterRenderer {
if (bgColor != null) {
g.setColor(bgColor);
}
g.fillRect(0, r.y, THICKNESS, r.height);
g.fillRect(r.x, r.y, r.width, r.height);
final LineData lineData = getLineData(editor.xyToLogicalPosition(new Point(0, r.y)).line);
if (lineData != null && lineData.isCoveredByOneTest()) {
g.drawImage( ImageLoader.loadFromResource("/gutter/unique.png"), 0, r.y, 8, 8, editor.getComponent());
g.drawImage( ImageLoader.loadFromResource("/gutter/unique.png"), r.x, r.y, 8, 8, editor.getComponent());
}
}
@@ -135,7 +148,12 @@ public class CoverageLineMarkerRenderer implements ActiveGutterRenderer {
}
public boolean canDoAction(final MouseEvent e) {
return e.getX() < THICKNESS;
Component component = e.getComponent();
if (component instanceof EditorGutterComponentEx) {
EditorGutterComponentEx gutter = (EditorGutterComponentEx)component;
return e.getX() > gutter.getLineMarkerAreaOffset() && e.getX() < gutter.getIconAreaOffset();
}
return false;
}
public void doAction(final Editor editor, final MouseEvent e) {
@@ -253,6 +271,11 @@ public class CoverageLineMarkerRenderer implements ActiveGutterRenderer {
return editor.getColorsScheme().getAttributes(myKey).getErrorStripeColor();
}
@Override
public Position getPosition() {
return Position.LEFT;
}
private class GotoPreviousCoveredLineAction extends BaseGotoCoveredLineAction {
public GotoPreviousCoveredLineAction(final Editor editor, final int lineNumber) {
+1 -1
View File
@@ -40,7 +40,7 @@
<deadCode implementation="com.intellij.execution.junit2.inspection.JUnitEntryPoint"/>
<cantBeStatic implementation="com.intellij.execution.junit2.inspection.JUnitCantBeStaticExtension" />
<testFramework implementation="com.intellij.execution.junit.JUnit3Framework"/>
<testFramework implementation="com.intellij.execution.junit.JUnit4Framework"/>
<testFramework implementation="com.intellij.execution.junit.JUnit4Framework" id="junit4"/>
<configurationType implementation="com.intellij.execution.junit.JUnitConfigurationType"/>
<library.dependencyScopeSuggester implementation="com.intellij.execution.junit.JUnitDependencyScopeSuggester"/>
@@ -17,6 +17,7 @@
package com.intellij.execution.junit;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.junit2.info.LocationUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
@@ -31,6 +32,14 @@ import org.jetbrains.jps.model.java.JavaSourceRootType;
public class AllInDirectoryConfigurationProducer extends JUnitConfigurationProducer {
protected AllInDirectoryConfigurationProducer(ConfigurationType configurationType) {
super(configurationType);
}
public AllInDirectoryConfigurationProducer() {
}
@Override
protected boolean setupConfigurationFromContext(JUnitConfiguration configuration,
ConfigurationContext context,
@@ -18,6 +18,7 @@ package com.intellij.execution.junit;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.junit2.info.LocationUtil;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
@@ -25,6 +26,14 @@ import com.intellij.psi.PsiPackage;
public class AllInPackageConfigurationProducer extends JUnitConfigurationProducer {
public AllInPackageConfigurationProducer() {
}
protected AllInPackageConfigurationProducer(ConfigurationType configurationType) {
super(configurationType);
}
@Override
protected boolean setupConfigurationFromContext(JUnitConfiguration configuration,
ConfigurationContext context,
@@ -23,6 +23,7 @@ import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
import com.intellij.openapi.module.Module;
@@ -36,6 +37,10 @@ public abstract class JUnitConfigurationProducer extends JavaRunConfigurationPro
super(JUnitConfigurationType.getInstance());
}
protected JUnitConfigurationProducer(ConfigurationType configurationType) {
super(configurationType);
}
@Override
public boolean isPreferredConfiguration(ConfigurationFromContext self, ConfigurationFromContext other) {
return !other.isProducedBy(TestMethodConfigurationProducer.class);
@@ -21,6 +21,7 @@ import com.intellij.execution.Location;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Ref;
@@ -31,6 +32,13 @@ import com.intellij.psi.PsiMethod;
import java.util.List;
public class TestClassConfigurationProducer extends JUnitConfigurationProducer {
public TestClassConfigurationProducer() {
}
protected TestClassConfigurationProducer(ConfigurationType configurationType) {
super(configurationType);
}
@Override
protected boolean setupConfigurationFromContext(JUnitConfiguration configuration,
ConfigurationContext context,
@@ -22,6 +22,7 @@ import com.intellij.execution.PsiLocation;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.openapi.module.Module;
@@ -35,6 +36,13 @@ import java.util.Iterator;
import java.util.List;
public class TestMethodConfigurationProducer extends JUnitConfigurationProducer {
public TestMethodConfigurationProducer() {
}
protected TestMethodConfigurationProducer(ConfigurationType configurationType) {
super(configurationType);
}
@Override
protected boolean setupConfigurationFromContext(JUnitConfiguration configuration,
ConfigurationContext context,
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -92,6 +92,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
myShortcutsManager = shortcutsManager;
}
@Override
public MavenProjectsNavigatorState getState() {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myStructure != null) {
@@ -106,6 +107,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
return myState;
}
@Override
public void loadState(MavenProjectsNavigatorState state) {
myState = state;
scheduleStructureUpdate();
@@ -183,6 +185,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
listenForProjectsChanges();
if (isUnitTestMode()) return;
MavenUtil.runWhenInitialized(myProject, new DumbAwareRunnable() {
@Override
public void run() {
if (myProject.isDisposed()) return;
initToolWindow();
@@ -200,8 +203,10 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
myProjectsManager.addProjectsTreeListener(new MyProjectsListener());
myShortcutsManager.addListener(new MavenShortcutsManager.Listener() {
@Override
public void shortcutsUpdated() {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateGoals();
}
@@ -210,8 +215,10 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
});
myTasksManager.addListener(new MavenTasksManager.Listener() {
@Override
public void compileTasksChanged() {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateGoals();
}
@@ -220,8 +227,10 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
});
RunManagerEx.getInstanceEx(myProject).addRunManagerListener(new RunManagerAdapter() {
@Override
public void beforeRunTasksChanged() {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateGoals();
}
@@ -233,6 +242,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
@Override
public void skipTestsChanged() {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateGoals();
}
@@ -243,6 +253,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
((RunManagerEx)RunManager.getInstance(myProject)).addRunManagerListener(new RunManagerAdapter() {
private void changed() {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateRunConfigurations();
}
@@ -291,9 +302,11 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
public void stateChanged() {
if (myToolWindow.isDisposed()) return;
boolean visible = myToolWindow.isVisible();
if (!visible || visible == wasVisible) return;
if (!visible || wasVisible) {
return;
}
scheduleStructureUpdate();
wasVisible = visible;
wasVisible = true;
}
};
manager.addToolWindowManagerListener(listener, myProject);
@@ -350,6 +363,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
public void selectInTree(final MavenProject project) {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.select(project);
}
@@ -364,6 +378,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
if (myToolWindow == null) return;
MavenUtil.invokeLater(myProject, new Runnable() {
@Override
public void run() {
if (!myToolWindow.isVisible()) return;
@@ -396,6 +411,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
private void scheduleStructureUpdate() {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.update();
}
@@ -403,10 +419,12 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
}
private class MyProjectsListener extends MavenProjectsTree.ListenerAdapter implements MavenProjectsManager.Listener {
@Override
public void activated() {
scheduleStructureUpdate();
}
@Override
public void projectsScheduled() {
}
@@ -417,6 +435,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
@Override
public void projectsIgnoredStateChanged(final List<MavenProject> ignored, final List<MavenProject> unignored, boolean fromImport) {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateIgnored(ContainerUtil.concat(ignored, unignored));
}
@@ -426,6 +445,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
@Override
public void profilesChanged() {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateProfiles();
}
@@ -437,17 +457,20 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen
scheduleUpdateProjects(MavenUtil.collectFirsts(updated), deleted);
}
@Override
public void projectResolved(Pair<MavenProject, MavenProjectChanges> projectWithChanges,
NativeMavenProjectHolder nativeMavenProject) {
scheduleUpdateProjects(Collections.singletonList(projectWithChanges.first), Collections.<MavenProject>emptyList());
}
@Override
public void pluginsResolved(MavenProject project) {
scheduleUpdateProjects(Collections.singletonList(project), Collections.<MavenProject>emptyList());
}
private void scheduleUpdateProjects(final List<MavenProject> projects, final List<MavenProject> deleted) {
scheduleStructureRequest(new Runnable() {
@Override
public void run() {
myStructure.updateProjects(projects, deleted);
}
+1 -1
View File
@@ -57,7 +57,7 @@
groupName="TestNG" enabledByDefault="true" level="ERROR"
implementationClass="com.theoryinpractice.testng.inspection.DataProviderReturnTypeInspection"/>
<testFramework implementation="com.theoryinpractice.testng.TestNGFramework"/>
<testFramework implementation="com.theoryinpractice.testng.TestNGFramework" id="testNG"/>
<codeInsight.externalLibraryResolver implementation="com.theoryinpractice.testng.intention.TestNGExternalLibraryResolver"/>
<standardResource url="http://testng.org/testng-1.0.dtd" path="resources/standardSchemas/testng-1.0.dtd"/>
<overrideImplementsAnnotationsHandler implementation="com.theoryinpractice.testng.intention.OverrideImplementsTestNGAnnotationsHandler"/>
@@ -15,6 +15,8 @@
*/
package com.intellij.uiDesigner.designSurface;
import com.intellij.ide.ui.UISettings;
import com.intellij.ui.JBColor;
import com.intellij.ui.LightColors;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.SwingProperties;
@@ -457,7 +459,8 @@ public final class Painter {
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(PlatformColors.BLUE);
g2d.fillRect(0, 0, (int)stringBounds.getWidth(), (int)stringBounds.getHeight());
g2d.setColor(Color.WHITE);
g2d.setColor(JBColor.WHITE);
UISettings.setupAntialiasing(g);
g.drawString(tagBuilder.toString(), 0, g.getFontMetrics().getAscent());
}
}
@@ -393,6 +393,7 @@ message.node.all.array.elements.null=All elements in range ({0}, {1}) are null
message.node.all.elements.null=All elements are null
message.node.empty.array=Empty
message.node.class.has.no.fields=Class has no fields
message.node.class.no.fields.to.display=No fields to display
message.node.object.collected=Object has been garbage collected during method invocation
message.node.thread.running=Thread is running
message.node.thread.has.no.frames=Thread has no frames
@@ -115,7 +115,7 @@
<attribute name="usemap" type="%URL" />
</control>
<control name="ol" type="HtmlGenericControl" startTag="required" endTag="required" emptyAllowed="false"/>
<control name="option" type="HtmlGenericControl" startTag="required" endTag="optional" emptyAllowed="false" autoClosedBy="option"/>
<control name="option" type="HtmlGenericControl" startTag="required" endTag="optional" emptyAllowed="false" autoClosedBy="option,optgroup"/>
<control name="P" type="HtmlGenericControl" startTag="required" endTag="optional" emptyAllowed="false" autoClosedBy="p"/>
<control name="param" type="HtmlGenericControl" startTag="required" endTag="forbidden" emptyAllowed="true"/>