mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
-4
@@ -377,10 +377,6 @@ public class BackendCompilerWrapper {
|
||||
exitValue = process.waitFor();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
if (CompileDriver.ourDebugMode) {
|
||||
System.out.println("Compiler interrupted; ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
process.destroy();
|
||||
exitValue = process.exitValue();
|
||||
}
|
||||
|
||||
+1
-43
@@ -48,8 +48,6 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback {
|
||||
private volatile boolean myProcessExited = false;
|
||||
private final CompileContext myContext;
|
||||
|
||||
//private final BlockingQueue<String> myLines = new LinkedBlockingQueue<String>();
|
||||
|
||||
public CompilerParsingThread(Process process, OutputParser outputParser, final boolean readErrorStream, boolean trimLines, CompileContext context) {
|
||||
myProcess = process;
|
||||
myOutputParser = outputParser;
|
||||
@@ -62,24 +60,6 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback {
|
||||
|
||||
volatile boolean processing;
|
||||
public void run() {
|
||||
//if (CompileDriver.ourDebugMode) {
|
||||
// ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// while (true) {
|
||||
// final String line = readLine(myCompilerOutStreamReader);
|
||||
// if (CompileDriver.ourDebugMode) {
|
||||
// System.out.println("RAW_LIne read: #" + line + "#");
|
||||
// }
|
||||
// if (line == null) {
|
||||
// myLines.offer(TERMINATION_STRING);
|
||||
// break;
|
||||
// }
|
||||
// myLines.offer(line);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
processing = true;
|
||||
try {
|
||||
while (true) {
|
||||
@@ -131,7 +111,7 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback {
|
||||
myLastReadLine = pushBack;
|
||||
return pushBack;
|
||||
}
|
||||
final String line = getNextUnprocessedLine();
|
||||
final String line = readLine(myCompilerOutStreamReader);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("LIne read: #" + line + "#");
|
||||
}
|
||||
@@ -147,28 +127,6 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback {
|
||||
return myLastReadLine;
|
||||
}
|
||||
|
||||
private String getNextUnprocessedLine() {
|
||||
//if (CompileDriver.ourDebugMode) {
|
||||
// try {
|
||||
// if (TERMINATION_STRING.equals(myLines.peek())) {
|
||||
// return TERMINATION_STRING;
|
||||
// }
|
||||
// final String line = myLines.take();
|
||||
// if (TERMINATION_STRING.equals(line)) {
|
||||
// myLines.offer(TERMINATION_STRING); // pushback
|
||||
// }
|
||||
// return line;
|
||||
// }
|
||||
// catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// return TERMINATION_STRING;
|
||||
// }
|
||||
//}
|
||||
//else {
|
||||
return readLine(myCompilerOutStreamReader);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushBack(String line) {
|
||||
myLastReadLine = null;
|
||||
|
||||
@@ -338,9 +338,9 @@ public class ExceptionUtil {
|
||||
|
||||
@NotNull
|
||||
private static List<PsiClassType> getUnhandledExceptions(PsiMethod method,
|
||||
PsiElement element,
|
||||
PsiElement topElement,
|
||||
PsiSubstitutor substitutor) {
|
||||
PsiElement element,
|
||||
PsiElement topElement,
|
||||
PsiSubstitutor substitutor) {
|
||||
if (method == null || isArrayClone(method, element)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -445,6 +445,9 @@ public class ExceptionUtil {
|
||||
if (tryStatement.getTryBlock() == element && isCaught(tryStatement, exceptionType)) {
|
||||
return true;
|
||||
}
|
||||
if (tryStatement.getResourceList() == element && isCaught(tryStatement, exceptionType)) {
|
||||
return true;
|
||||
}
|
||||
PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
|
||||
if (element instanceof PsiCatchSection && finallyBlock != null && blockCompletesAbruptly(finallyBlock)) {
|
||||
// exception swallowed
|
||||
|
||||
+47
-20
@@ -13,14 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: cdr
|
||||
* Date: Jul 30, 2002
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorMessages;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
@@ -60,6 +56,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
* Date: Jul 30, 2002
|
||||
*/
|
||||
public class HighlightUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil");
|
||||
private static final Map<String, Set<String>> ourInterfaceIncompatibleModifiers;
|
||||
@@ -853,14 +853,23 @@ public class HighlightUtil {
|
||||
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkExceptionThrownInTry(final PsiParameter parameter) {
|
||||
static Collection<HighlightInfo> checkExceptionThrownInTry(final PsiParameter parameter) {
|
||||
final PsiElement declarationScope = parameter.getDeclarationScope();
|
||||
if (!(declarationScope instanceof PsiCatchSection)) return null;
|
||||
|
||||
final Set<PsiClassType> thrownTypes = Sets.newHashSet();
|
||||
|
||||
final PsiTryStatement statement = ((PsiCatchSection)declarationScope).getTryStatement();
|
||||
final PsiCodeBlock tryBlock = statement.getTryBlock();
|
||||
assert tryBlock != null : statement;
|
||||
final Collection<PsiClassType> thrownTypes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
|
||||
thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock));
|
||||
|
||||
final PsiParameterList resources = statement.getResourceList();
|
||||
if (resources != null) {
|
||||
thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(resources, resources));
|
||||
}
|
||||
|
||||
// todo: add exceptions from resource's close() method
|
||||
|
||||
final PsiType caughtType = parameter.getType();
|
||||
if (caughtType instanceof PsiClassType) {
|
||||
@@ -874,9 +883,9 @@ public class HighlightUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static HighlightInfo checkSimpleCatchParameter(final PsiParameter parameter,
|
||||
final Collection<PsiClassType> thrownTypes,
|
||||
final PsiClassType caughtType) {
|
||||
private static Collection<HighlightInfo> checkSimpleCatchParameter(final PsiParameter parameter,
|
||||
final Collection<PsiClassType> thrownTypes,
|
||||
final PsiClassType caughtType) {
|
||||
if (ExceptionUtil.isUncheckedExceptionOrSuperclass(caughtType)) return null;
|
||||
|
||||
for (PsiClassType exceptionType : thrownTypes) {
|
||||
@@ -886,12 +895,17 @@ public class HighlightUtil {
|
||||
final String description = JavaErrorMessages.message("exception.never.thrown.try", formatType(caughtType));
|
||||
final HighlightInfo errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameter, description);
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new DeleteCatchFix(parameter));
|
||||
return errorResult;
|
||||
return Lists.newArrayList(errorResult);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static HighlightInfo checkMultiCatchParameter(final PsiParameter parameter, final Collection<PsiClassType> thrownTypes) {
|
||||
for (PsiTypeElement typeElement : PsiTreeUtil.getChildrenOfTypeAsList(parameter.getTypeElement(), PsiTypeElement.class)) {
|
||||
private static Collection<HighlightInfo> checkMultiCatchParameter(final PsiParameter parameter,
|
||||
final Collection<PsiClassType> thrownTypes) {
|
||||
final List<PsiTypeElement> typeElements = PsiTreeUtil.getChildrenOfTypeAsList(parameter.getTypeElement(), PsiTypeElement.class);
|
||||
final Collection<HighlightInfo> highlights = Lists.newArrayListWithCapacity(typeElements.size());
|
||||
|
||||
for (int i = 0, size = typeElements.size(); i < size; i++) {
|
||||
final PsiTypeElement typeElement = typeElements.get(i);
|
||||
final PsiType catchType = typeElement.getType();
|
||||
if (catchType instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)catchType)) continue;
|
||||
|
||||
@@ -902,15 +916,28 @@ public class HighlightUtil {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (used) continue;
|
||||
if (!used) {
|
||||
final String description = JavaErrorMessages.message("exception.never.thrown.try", formatType(catchType));
|
||||
final HighlightInfo highlight = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeElement, description);
|
||||
QuickFixAction.registerQuickFixAction(highlight, new DeleteMultiCatchFix(typeElement));
|
||||
highlights.add(highlight);
|
||||
continue;
|
||||
}
|
||||
|
||||
final String description = JavaErrorMessages.message("exception.never.thrown.try", formatType(catchType));
|
||||
final HighlightInfo errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeElement, description);
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new DeleteMultiCatchFix(typeElement));
|
||||
return errorResult;
|
||||
for (int j = size - 1; j > i; j--) {
|
||||
final PsiTypeElement nextElement = typeElements.get(j);
|
||||
final PsiType nextType = nextElement.getType();
|
||||
if (nextType.isAssignableFrom(catchType)) {
|
||||
final String description = JavaErrorMessages.message("exception.double.caught.in.multi", formatType(catchType), formatType(nextType));
|
||||
final HighlightInfo highlight = HighlightInfo.createHighlightInfo(HighlightInfoType.WARNING, typeElement, description);
|
||||
QuickFixAction.registerQuickFixAction(highlight, new DeleteMultiCatchFix(typeElement));
|
||||
highlights.add(highlight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return highlights;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -899,7 +899,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (!myHolder.hasErrorResults()) {
|
||||
PsiParameter[] parameters = statement.getCatchBlockParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
myHolder.add(HighlightUtil.checkExceptionThrownInTry(parameter));
|
||||
myHolder.addAll(HighlightUtil.checkExceptionThrownInTry(parameter));
|
||||
myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter));
|
||||
myHolder.add(GenericsHighlightUtil.checkCatchParameterIsClass(parameter));
|
||||
}
|
||||
|
||||
@@ -447,26 +447,43 @@ public class DeclarationParser {
|
||||
|
||||
@NotNull
|
||||
public static PsiBuilder.Marker parseParameterList(final PsiBuilder builder) {
|
||||
return parseParameterList(builder, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiBuilder.Marker parseResourceList(final PsiBuilder builder) {
|
||||
return parseParameterList(builder, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiBuilder.Marker parseParameterList(final PsiBuilder builder, final boolean resources) {
|
||||
assert builder.getTokenType() == JavaTokenType.LPARENTH : builder.getTokenType();
|
||||
final PsiBuilder.Marker paramList = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
final IElementType delimiter = resources ? JavaTokenType.SEMICOLON : JavaTokenType.COMMA;
|
||||
final String noDelimiterMsg = JavaErrorMessages.message(resources ? "expected.semicolon" : "expected.comma");
|
||||
final String noParameterMsg = JavaErrorMessages.message(resources ? "expected.resource" : "expected.parameter");
|
||||
|
||||
PsiBuilder.Marker invalidElements = null;
|
||||
String errorMessage = null;
|
||||
boolean commaExpected = false;
|
||||
boolean delimiterExpected = false;
|
||||
int paramCount = 0;
|
||||
while (true) {
|
||||
final IElementType tokenType = builder.getTokenType();
|
||||
if (tokenType == null || tokenType == JavaTokenType.RPARENTH) {
|
||||
boolean noLastParam = !commaExpected && paramCount > 0;
|
||||
if (tokenType == null || tokenType == JavaTokenType.RPARENTH || tokenType == JavaTokenType.LBRACE) {
|
||||
boolean noLastParam = !delimiterExpected && paramCount > 0;
|
||||
if (noLastParam) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier.or.type"));
|
||||
}
|
||||
if (tokenType == JavaTokenType.RPARENTH) {
|
||||
if (invalidElements != null) {
|
||||
invalidElements.error(errorMessage);
|
||||
invalidElements = null;
|
||||
}
|
||||
else if (resources && paramCount == 0) {
|
||||
error(builder, JavaErrorMessages.message("expected.resource"));
|
||||
}
|
||||
invalidElements = null;
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
@@ -481,9 +498,9 @@ public class DeclarationParser {
|
||||
break;
|
||||
}
|
||||
|
||||
if (commaExpected) {
|
||||
if (builder.getTokenType() == JavaTokenType.COMMA) {
|
||||
commaExpected = false;
|
||||
if (delimiterExpected) {
|
||||
if (builder.getTokenType() == delimiter) {
|
||||
delimiterExpected = false;
|
||||
if (invalidElements != null) {
|
||||
invalidElements.error(errorMessage);
|
||||
invalidElements = null;
|
||||
@@ -493,9 +510,9 @@ public class DeclarationParser {
|
||||
}
|
||||
}
|
||||
else {
|
||||
final PsiBuilder.Marker param = parseParameter(builder, true, false);
|
||||
final PsiBuilder.Marker param = parseParameter(builder, true, false, resources);
|
||||
if (param != null) {
|
||||
commaExpected = true;
|
||||
delimiterExpected = true;
|
||||
if (invalidElements != null) {
|
||||
invalidElements.errorBefore(errorMessage, param);
|
||||
invalidElements = null;
|
||||
@@ -506,14 +523,14 @@ public class DeclarationParser {
|
||||
}
|
||||
|
||||
if (invalidElements == null) {
|
||||
if (builder.getTokenType() == JavaTokenType.COMMA) {
|
||||
error(builder, JavaErrorMessages.message("expected.parameter"));
|
||||
if (builder.getTokenType() == delimiter) {
|
||||
error(builder, noParameterMsg);
|
||||
builder.advanceLexer();
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
invalidElements = builder.mark();
|
||||
errorMessage = commaExpected ? JavaErrorMessages.message("expected.comma") : JavaErrorMessages.message("expected.parameter");
|
||||
errorMessage = delimiterExpected ? noDelimiterMsg : noParameterMsg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,14 +550,14 @@ public class DeclarationParser {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunctiveType) {
|
||||
public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunction, final boolean value) {
|
||||
final PsiBuilder.Marker param = builder.mark();
|
||||
|
||||
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
|
||||
|
||||
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
|
||||
if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
|
||||
if (disjunctiveType) flags |= ReferenceParser.DISJUNCTIONS;
|
||||
if (disjunction) flags |= ReferenceParser.DISJUNCTIONS;
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags);
|
||||
|
||||
if (typeInfo == null) {
|
||||
@@ -555,15 +572,23 @@ public class DeclarationParser {
|
||||
}
|
||||
|
||||
if (expect(builder, JavaTokenType.IDENTIFIER)) {
|
||||
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
|
||||
done(param, JavaElementType.PARAMETER);
|
||||
return param;
|
||||
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg || value, JavaErrorMessages.message("expected.rparen"));
|
||||
if (value) {
|
||||
if (expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"))) {
|
||||
if (ExpressionParser.parse(builder) == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.expression"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
param.drop();
|
||||
return modListInfo.first;
|
||||
}
|
||||
|
||||
done(param, JavaElementType.PARAMETER);
|
||||
return param;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -138,14 +138,16 @@ public class JavaParserUtil {
|
||||
builder.putUserDataUnprotected(LANG_LEVEL_KEY, level);
|
||||
}
|
||||
|
||||
// todo[r.sh] join all JDK 7 check clauses into single method (IDEA 11)
|
||||
public static boolean areDiamondsSupported(final PsiBuilder builder) {
|
||||
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7);
|
||||
}
|
||||
|
||||
// todo[r.sh] join all JDK 7 check clauses into single method (IDEA 11)
|
||||
public static boolean areMultiCatchSupported(final PsiBuilder builder) {
|
||||
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7);
|
||||
}
|
||||
public static boolean areTryWithResourcesSupported(final PsiBuilder builder) {
|
||||
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7);
|
||||
}
|
||||
|
||||
public static boolean areTypeAnnotationsSupported(final PsiBuilder builder) {
|
||||
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_8);
|
||||
|
||||
@@ -375,7 +375,7 @@ public class StatementParser {
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker afterParenth = builder.mark();
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, false);
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, false, false);
|
||||
if (param == null || JavaParserUtil.exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) {
|
||||
afterParenth.rollbackTo();
|
||||
return parseForLoopFromInitialization(builder, statement);
|
||||
@@ -612,6 +612,12 @@ public class StatementParser {
|
||||
final PsiBuilder.Marker statement = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
boolean hasResourceList = false;
|
||||
if (areTryWithResourcesSupported(builder) && builder.getTokenType() == JavaTokenType.LPARENTH) {
|
||||
hasResourceList = true;
|
||||
DeclarationParser.parseResourceList(builder);
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker tryBlock = parseCodeBlock(builder, true);
|
||||
if (tryBlock == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.lbrace"));
|
||||
@@ -619,7 +625,7 @@ public class StatementParser {
|
||||
return statement;
|
||||
}
|
||||
|
||||
if (!TRY_CLOSERS_SET.contains(builder.getTokenType())) {
|
||||
if (!hasResourceList && !TRY_CLOSERS_SET.contains(builder.getTokenType())) {
|
||||
error(builder, JavaErrorMessages.message("expected.catch.or.finally"));
|
||||
done(statement, JavaElementType.TRY_STATEMENT);
|
||||
return statement;
|
||||
@@ -651,7 +657,7 @@ public class StatementParser {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, areMultiCatchSupported(builder));
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, areMultiCatchSupported(builder), false);
|
||||
if (param == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.parameter"));
|
||||
}
|
||||
|
||||
@@ -173,11 +173,11 @@ public class PsiImplUtil {
|
||||
return processor.getResults().toArray();
|
||||
}
|
||||
|
||||
public static boolean processDeclarationsInMethod(PsiMethod method,
|
||||
@NotNull PsiScopeProcessor processor,
|
||||
ResolveState state,
|
||||
PsiElement lastParent,
|
||||
PsiElement place) {
|
||||
public static boolean processDeclarationsInMethod(@NotNull final PsiMethod method,
|
||||
@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state,
|
||||
final PsiElement lastParent,
|
||||
@NotNull final PsiElement place) {
|
||||
final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
|
||||
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, method);
|
||||
if (hint == null || hint.shouldProcess(ElementClassHint.DeclaractionKind.CLASS)) {
|
||||
@@ -185,15 +185,35 @@ public class PsiImplUtil {
|
||||
if (list != null && !list.processDeclarations(processor, state, null, place)) return false;
|
||||
}
|
||||
if (lastParent instanceof PsiCodeBlock) {
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!processor.execute(parameter, state)) return false;
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (processDeclarationsInParameterList(parameterList, processor, state)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean processDeclarationsInTryStatement(@NotNull final PsiTryStatement statement,
|
||||
@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state,
|
||||
final PsiElement lastParent) {
|
||||
if (lastParent instanceof PsiCodeBlock) {
|
||||
final PsiParameterList parameterList = statement.getResourceList();
|
||||
if (parameterList != null && processDeclarationsInParameterList(parameterList, processor, state)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean processDeclarationsInParameterList(@NotNull final PsiParameterList parameterList,
|
||||
@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state) {
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!processor.execute(parameter, state)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasTypeParameters(@NotNull PsiTypeParameterListOwner owner) {
|
||||
final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
|
||||
return typeParameterList != null && typeParameterList.getTypeParameters().length != 0;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.intellij.psi.impl;
|
||||
|
||||
import com.intellij.ide.fileTemplates.FileTemplate;
|
||||
@@ -45,7 +44,7 @@ import java.util.Properties;
|
||||
|
||||
import static com.intellij.openapi.util.text.StringUtil.join;
|
||||
|
||||
/*
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJavaParserFacade {
|
||||
@@ -61,7 +60,14 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
|
||||
private static final JavaParserUtil.ParserWrapper PARAMETER = new JavaParserUtil.ParserWrapper() {
|
||||
@Override
|
||||
public void parse(final PsiBuilder builder) {
|
||||
DeclarationParser.parseParameter(builder, true, false);
|
||||
DeclarationParser.parseParameter(builder, true, false, false);
|
||||
}
|
||||
};
|
||||
|
||||
private static final JavaParserUtil.ParserWrapper RESOURCE = new JavaParserUtil.ParserWrapper() {
|
||||
@Override
|
||||
public void parse(final PsiBuilder builder) {
|
||||
DeclarationParser.parseParameter(builder, true, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -233,7 +239,10 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
|
||||
|
||||
@NotNull
|
||||
public PsiParameter createParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException {
|
||||
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, PARAMETER, false), context);
|
||||
final boolean resource = context instanceof PsiParameterList &&
|
||||
context.getParent() instanceof PsiTryStatement;
|
||||
final JavaParserUtil.ParserWrapper wrapper = resource ? RESOURCE : PARAMETER;
|
||||
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, wrapper, false), context);
|
||||
final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode());
|
||||
if (!(element instanceof PsiParameter)) {
|
||||
throw new IncorrectOperationException("Incorrect parameter \"" + text + "\".");
|
||||
|
||||
@@ -49,10 +49,7 @@ public class JavaLightStubBuilder extends LightStubBuilder {
|
||||
|
||||
@Override
|
||||
public boolean skipChildProcessingWhenBuildingStubs(final IElementType nodeType, final IElementType childType) {
|
||||
if (childType == JavaElementType.PARAMETER && nodeType != JavaElementType.PARAMETER_LIST) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return childType == JavaElementType.PARAMETER_LIST && nodeType != JavaElementType.METHOD && nodeType != JavaElementType.ANNOTATION_METHOD ||
|
||||
childType == JavaElementType.PARAMETER && nodeType != JavaElementType.PARAMETER_LIST;
|
||||
}
|
||||
}
|
||||
@@ -18,29 +18,33 @@ package com.intellij.psi.impl.source.tree.java;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
|
||||
import com.intellij.psi.impl.PsiImplUtil;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
|
||||
import com.intellij.psi.impl.source.tree.ChildRole;
|
||||
import com.intellij.psi.impl.source.tree.CompositePsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.tree.ChildRoleBase;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PsiTryStatementImpl extends CompositePsiElement implements PsiTryStatement, Constants {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiTryStatementImpl");
|
||||
|
||||
private volatile PsiParameter[] myCachedCatchParameters = null;
|
||||
|
||||
public PsiTryStatementImpl() {
|
||||
super(TRY_STATEMENT);
|
||||
}
|
||||
|
||||
public void clearCaches() {
|
||||
super.clearCaches();
|
||||
myCachedCatchParameters = null;
|
||||
}
|
||||
|
||||
public PsiTryStatementImpl() {
|
||||
super(TRY_STATEMENT);
|
||||
}
|
||||
|
||||
public PsiCodeBlock getTryBlock() {
|
||||
return (PsiCodeBlock)findChildByRoleAsPsiElement(ChildRole.TRY_BLOCK);
|
||||
}
|
||||
@@ -88,6 +92,11 @@ public class PsiTryStatementImpl extends CompositePsiElement implements PsiTrySt
|
||||
return (PsiCodeBlock)findChildByRoleAsPsiElement(ChildRole.FINALLY_BLOCK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiParameterList getResourceList() {
|
||||
return PsiTreeUtil.findChildOfType(this, PsiParameterList.class);
|
||||
}
|
||||
|
||||
public ASTNode findChildByRole(int role) {
|
||||
LOG.assertTrue(ChildRole.isUnique(role));
|
||||
switch(role){
|
||||
@@ -150,6 +159,14 @@ public class PsiTryStatementImpl extends CompositePsiElement implements PsiTrySt
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDeclarations(@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state,
|
||||
final PsiElement lastParent,
|
||||
@NotNull final PsiElement place) {
|
||||
return PsiImplUtil.processDeclarationsInTryStatement(this, processor, state, lastParent);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "PsiTryStatement";
|
||||
}
|
||||
|
||||
+3
-27
@@ -30,13 +30,11 @@ import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.refactoring.MoveDestination;
|
||||
import com.intellij.refactoring.PackageWrapper;
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo;
|
||||
import com.intellij.refactoring.util.NonCodeUsageInfo;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.refactoring.util.TextOccurrencesUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
@@ -97,31 +95,9 @@ public class MoveClassesOrPackagesUtil {
|
||||
final PsiElement element,
|
||||
final String newQName,
|
||||
ArrayList<UsageInfo> results) {
|
||||
if (searchInStringsAndComments || searchInNonJavaFiles) {
|
||||
final String stringToSearch = getStringToSearch(element);
|
||||
if (stringToSearch == null) return;
|
||||
TextOccurrencesUtil.UsageInfoFactory factory = createUsageInfoFactory(element, newQName);
|
||||
|
||||
if (searchInStringsAndComments) {
|
||||
TextOccurrencesUtil.addUsagesInStringsAndComments(element, stringToSearch, results, factory);
|
||||
}
|
||||
|
||||
if (searchInNonJavaFiles) {
|
||||
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(element.getProject());
|
||||
TextOccurrencesUtil.addTextOccurences(element, stringToSearch, projectScope, results, factory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TextOccurrencesUtil.UsageInfoFactory createUsageInfoFactory(final PsiElement element,
|
||||
final String newQName) {
|
||||
return new TextOccurrencesUtil.UsageInfoFactory() {
|
||||
public UsageInfo createUsageInfo(@NotNull PsiElement usage, int startOffset, int endOffset) {
|
||||
int start = usage.getTextRange().getStartOffset();
|
||||
return NonCodeUsageInfo.create(usage.getContainingFile(), start + startOffset, start + endOffset, element,
|
||||
newQName);
|
||||
}
|
||||
};
|
||||
final String stringToSearch = getStringToSearch(element);
|
||||
if (stringToSearch == null) return;
|
||||
TextOccurrencesUtil.findNonCodeUsages(element, stringToSearch, searchInStringsAndComments, searchInNonJavaFiles, newQName, results);
|
||||
}
|
||||
|
||||
private static String getStringToSearch(PsiElement element) {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import pack.AClass;
|
||||
import pack.AAClass;
|
||||
|
||||
public class Test1 {
|
||||
public void foo() {
|
||||
new AClass()<caret>
|
||||
new AAClass()<caret>
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
public class Test1 {
|
||||
public void foo() {
|
||||
new ACl<caret>
|
||||
new AACl<caret>
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package pack;
|
||||
|
||||
public class AAClass {
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
package pack;
|
||||
|
||||
public class AClass{
|
||||
}
|
||||
+2
-1
@@ -4,6 +4,7 @@ abstract class C {
|
||||
private static class E1 extends E { }
|
||||
private static class E2 extends E { }
|
||||
private static class E3 extends E { }
|
||||
private static class E4 extends E { }
|
||||
private static class RE extends RuntimeException { }
|
||||
private interface I<T> { }
|
||||
private static class IE1 extends E implements I<Integer> { }
|
||||
@@ -23,7 +24,7 @@ abstract class C {
|
||||
try { g(); } catch (IE1 | IE2 e) { new F<I<? extends Number>>(e); }
|
||||
|
||||
try { f(); } catch (E1 | E2 | <error descr="Exception 'C.E3' is never thrown in the corresponding try block">E3</error> e) { }
|
||||
try { f(); } catch (<error descr="Exception 'C.E3' is never thrown in the corresponding try block">E3</error> | E e) { }
|
||||
try { f(); } catch (<error descr="Exception 'C.E3' is never thrown in the corresponding try block">E3</error> | <error descr="Exception 'C.E4' is never thrown in the corresponding try block">E4</error> | E e) { }
|
||||
|
||||
try { f(); } catch (E | <error descr="Exception 'C.E1' has already been caught">E1</error> e) { }
|
||||
try { f(); } catch (E | <error descr="Exception 'C.E3' has already been caught">E3</error> e) { }
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
abstract class C {
|
||||
private static class E extends Exception { }
|
||||
private static class E1 extends E { }
|
||||
private static class E2 extends E { }
|
||||
|
||||
abstract void f() throws E1, E2;
|
||||
|
||||
void m() {
|
||||
try { f(); } catch (E1 | E2 ignore) { }
|
||||
try { f(); } catch (<warning descr="Exception 'C.E1' is also caught by 'C.E'">E1</warning> | E ignore) { }
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import java.io.*;
|
||||
import java.lang.Exception;
|
||||
|
||||
class C {
|
||||
void m0() throws Exception {
|
||||
try (FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
reader.read();
|
||||
} catch (Exception e) {
|
||||
<error descr="Cannot resolve symbol 'reader'">reader</error> = null;
|
||||
}
|
||||
<error descr="Cannot resolve symbol 'reader'">reader</error> = null;
|
||||
}
|
||||
|
||||
void m1() {
|
||||
try (final FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
reader.read();
|
||||
}
|
||||
catch (IOException ignore) { }
|
||||
|
||||
try (final FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
System.out.println("Try.");
|
||||
}
|
||||
catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
/*void m2() throws IOException {
|
||||
try (final FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
reader.read();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
PsiJavaFile:TryIncomplete10.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiErrorElement:')' expected
|
||||
<empty list>
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,11 @@
|
||||
PsiJavaFile:TryIncomplete11.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:()
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiErrorElement:Resource definition expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,14 @@
|
||||
PsiJavaFile:TryIncomplete12.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(;)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiErrorElement:Resource definition expected
|
||||
<empty list>
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiErrorElement:Resource definition expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,18 @@
|
||||
PsiJavaFile:TryIncomplete13.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(final )
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiModifierList:final
|
||||
PsiKeyword:final('final')
|
||||
PsiErrorElement:Type expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeElement:
|
||||
<empty list>
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,18 @@
|
||||
PsiJavaFile:TryIncomplete14.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
PsiJavaCodeReferenceElement:R
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,21 @@
|
||||
PsiJavaFile:TryIncomplete15.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
PsiJavaCodeReferenceElement:R
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r('r')
|
||||
PsiErrorElement:'=' expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,23 @@
|
||||
PsiJavaFile:TryIncomplete16.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r =)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
PsiJavaCodeReferenceElement:R
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r('r')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:EQ('=')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,27 @@
|
||||
PsiJavaFile:TryIncomplete17.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r = 0;)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
PsiJavaCodeReferenceElement:R
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r('r')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:EQ('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiLiteralExpression:0
|
||||
PsiJavaToken:INTEGER_LITERAL('0')
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiErrorElement:Identifier or type expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,25 @@
|
||||
PsiJavaFile:TryIncomplete8.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiCatchSection
|
||||
PsiKeyword:catch('catch')
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:A|
|
||||
PsiTypeElement:A
|
||||
PsiJavaCodeReferenceElement:A
|
||||
PsiIdentifier:A('A')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:OR('|')
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiErrorElement:'{' expected
|
||||
<empty list>
|
||||
@@ -0,0 +1,28 @@
|
||||
PsiJavaFile:TryIncomplete9.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiCatchSection
|
||||
PsiKeyword:catch('catch')
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:A|B
|
||||
PsiTypeElement:A
|
||||
PsiJavaCodeReferenceElement:A
|
||||
PsiIdentifier:A('A')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:OR('|')
|
||||
PsiTypeElement:B
|
||||
PsiJavaCodeReferenceElement:B
|
||||
PsiIdentifier:B('B')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiErrorElement:'{' expected
|
||||
<empty list>
|
||||
@@ -8,8 +8,9 @@ PsiJavaFile:TryNormal1.java
|
||||
PsiKeyword:catch('catch')
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:e
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiModifierList:final
|
||||
PsiKeyword:final('final')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeElement:E
|
||||
PsiJavaCodeReferenceElement:E
|
||||
PsiIdentifier:E('E')
|
||||
@@ -24,4 +25,4 @@ PsiJavaFile:TryNormal1.java
|
||||
PsiKeyword:finally('finally')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
PsiJavaFile:TryNormal3.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiCatchSection
|
||||
PsiKeyword:catch('catch')
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:e
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:A|B
|
||||
PsiTypeElement:A
|
||||
PsiJavaCodeReferenceElement:A
|
||||
PsiIdentifier:A('A')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:OR('|')
|
||||
PsiTypeElement:B
|
||||
PsiJavaCodeReferenceElement:B
|
||||
PsiIdentifier:B('B')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:e('e')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,24 @@
|
||||
PsiJavaFile:TryNormal4.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r = 0)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
PsiJavaCodeReferenceElement:R
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r('r')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:EQ('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiLiteralExpression:0
|
||||
PsiJavaToken:INTEGER_LITERAL('0')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,41 @@
|
||||
PsiJavaFile:TryNormal5.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R1 r1 = 1; R2 r2 = 2)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r1
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R1
|
||||
PsiJavaCodeReferenceElement:R1
|
||||
PsiIdentifier:R1('R1')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r1('r1')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:EQ('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiLiteralExpression:1
|
||||
PsiJavaToken:INTEGER_LITERAL('1')
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiParameter:r2
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R2
|
||||
PsiJavaCodeReferenceElement:R2
|
||||
PsiIdentifier:R2('R2')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r2('r2')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:EQ('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiLiteralExpression:2
|
||||
PsiJavaToken:INTEGER_LITERAL('2')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
+9
-1
@@ -153,7 +153,15 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testMultiCatch() throws Exception {
|
||||
doTest(false, false);
|
||||
}
|
||||
|
||||
|
||||
public void testMultiCatchWarn() throws Exception {
|
||||
doTest(true, false);
|
||||
}
|
||||
|
||||
public void testTryWithResources() throws Exception {
|
||||
doTest(false, false);
|
||||
}
|
||||
|
||||
public void testSafeVarargsApplicability() throws Exception {
|
||||
doTest(true, false);
|
||||
}
|
||||
|
||||
+24
-1
@@ -18,6 +18,7 @@ package com.intellij.lang.java.parser.partial;
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.lang.java.parser.JavaParsingTestCase;
|
||||
import com.intellij.lang.java.parser.StatementParser;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
|
||||
|
||||
public class StatementParserTest extends JavaParsingTestCase {
|
||||
@@ -116,8 +117,11 @@ public class StatementParserTest extends JavaParsingTestCase {
|
||||
public void testThrowIncomplete1() { doParserTest("throw e"); }
|
||||
|
||||
public void testTryNormal0() { doParserTest("try{}catch(E e){}"); }
|
||||
public void testTryNormal1() { doParserTest("try{}catch(E e){}finally{}"); }
|
||||
public void testTryNormal1() { doParserTest("try{}catch(final E e){}finally{}"); }
|
||||
public void testTryNormal2() { doParserTest("try{}finally{}"); }
|
||||
public void testTryNormal3() { doParserTestJDK7("try{}catch(A|B e){}"); }
|
||||
public void testTryNormal4() { doParserTestJDK7("try(R r = 0){}"); }
|
||||
public void testTryNormal5() { doParserTestJDK7("try(R1 r1 = 1; R2 r2 = 2){}"); }
|
||||
public void testTryIncomplete0() { doParserTest("try"); }
|
||||
public void testTryIncomplete1() { doParserTest("try{}"); }
|
||||
public void testTryIncomplete2() { doParserTest("try{}catch"); }
|
||||
@@ -126,6 +130,16 @@ public class StatementParserTest extends JavaParsingTestCase {
|
||||
public void testTryIncomplete5() { doParserTest("try{}catch(E e"); }
|
||||
public void testTryIncomplete6() { doParserTest("try{}catch(E e)"); }
|
||||
public void testTryIncomplete7() { doParserTest("try{}finally"); }
|
||||
public void testTryIncomplete8() { doParserTestJDK7("try{}catch(A|)"); }
|
||||
public void testTryIncomplete9() { doParserTestJDK7("try{}catch(A|B)"); }
|
||||
public void testTryIncomplete10() { doParserTestJDK7("try({}"); }
|
||||
public void testTryIncomplete11() { doParserTestJDK7("try(){}"); }
|
||||
public void testTryIncomplete12() { doParserTestJDK7("try(;){}"); }
|
||||
public void testTryIncomplete13() { doParserTestJDK7("try(final ){}"); }
|
||||
public void testTryIncomplete14() { doParserTestJDK7("try(R){}"); }
|
||||
public void testTryIncomplete15() { doParserTestJDK7("try(R r){}"); }
|
||||
public void testTryIncomplete16() { doParserTestJDK7("try(R r =){}"); }
|
||||
public void testTryIncomplete17() { doParserTestJDK7("try(R r = 0;){}"); }
|
||||
|
||||
public void testWhileNormal() { doParserTest("while (true) foo();"); }
|
||||
public void testWhileIncomplete0() { doParserTest("while"); }
|
||||
@@ -152,4 +166,13 @@ public class StatementParserTest extends JavaParsingTestCase {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doParserTestJDK7(final String text) {
|
||||
withLevel(LanguageLevel.JDK_1_7, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doParserTest(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ public class NavigateFromSourceTest extends BaseProjectViewTestCase {
|
||||
" -PsiDirectory: src\n" +
|
||||
" -PsiDirectory: com\n" +
|
||||
" -PsiDirectory: package1\n" +
|
||||
" [Class11]\n" +
|
||||
" -Class1.java\n" +
|
||||
" [Class11]\n" +
|
||||
" Class2\n" +
|
||||
getRootFiles() +
|
||||
" +External Libraries\n");
|
||||
@@ -82,7 +83,8 @@ public class NavigateFromSourceTest extends BaseProjectViewTestCase {
|
||||
" -PsiDirectory: src\n" +
|
||||
" -PsiDirectory: com\n" +
|
||||
" -PsiDirectory: package1\n" +
|
||||
" [Class1]\n" +
|
||||
" -Class1.java\n" +
|
||||
" [Class1]\n" +
|
||||
" Class2\n" +
|
||||
getRootFiles() +
|
||||
" +External Libraries\n");
|
||||
|
||||
@@ -296,6 +296,28 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
public void testNonMethodParameterLists() {
|
||||
withLevel(LanguageLevel.JDK_1_7, new Runnable() {
|
||||
@Override public void run() {
|
||||
doTest("class C {\n" +
|
||||
" {\n" +
|
||||
" try (Resource r = new Resource()) { }\n" +
|
||||
" }\n" +
|
||||
"}",
|
||||
|
||||
"PsiJavaFileStub []\n" +
|
||||
" IMPORT_LIST:PsiImportListStub\n" +
|
||||
" CLASS:PsiClassStub[name=C fqn=C]\n" +
|
||||
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" +
|
||||
" TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" +
|
||||
" EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" +
|
||||
" IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" +
|
||||
" CLASS_INITIALIZER:PsiClassInitializerStub\n" +
|
||||
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testSOEProof() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final SecureRandom random = new SecureRandom();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -64,4 +64,12 @@ public interface PsiTryStatement extends PsiStatement {
|
||||
*/
|
||||
@Nullable
|
||||
PsiCodeBlock getFinallyBlock();
|
||||
|
||||
/**
|
||||
* Returns a resource list of try-with-resources statement.
|
||||
*
|
||||
* @return resource list, or null if the statement doesn't have it.
|
||||
*/
|
||||
@Nullable
|
||||
PsiParameterList getResourceList();
|
||||
}
|
||||
|
||||
@@ -46,5 +46,6 @@ public interface SmartPsiElementPointer<E extends PsiElement> {
|
||||
|
||||
VirtualFile getVirtualFile();
|
||||
|
||||
@Nullable
|
||||
Segment getRange();
|
||||
}
|
||||
|
||||
@@ -136,6 +136,13 @@ public class UsageInfo {
|
||||
}
|
||||
|
||||
public int getNavigationOffset() {
|
||||
if (mySmartPointer instanceof SmartPsiFileRange) {
|
||||
final Segment range = mySmartPointer.getRange();
|
||||
if (range != null) {
|
||||
return range.getStartOffset();
|
||||
}
|
||||
}
|
||||
|
||||
PsiElement element = getElement();
|
||||
if (element == null) return -1;
|
||||
TextRange range = element.getTextRange();
|
||||
@@ -145,6 +152,7 @@ public class UsageInfo {
|
||||
return range.getStartOffset() + rangeInElement.getStartOffset();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Segment getSegment() {
|
||||
PsiElement element = getElement();
|
||||
if (element == null) return null;
|
||||
|
||||
+1
-1
@@ -28,8 +28,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author max
|
||||
*/
|
||||
public class ReformatAndOptimizeImportsProcessor extends AbstractLayoutCodeProcessor {
|
||||
public static final String COMMAND_NAME = CodeInsightBundle.message("progress.reformat.code.prepare");
|
||||
private static final String PROGRESS_TEXT = CodeInsightBundle.message("reformat.progress.common.text");
|
||||
private static final String COMMAND_NAME = CodeInsightBundle.message("progress.reformat.code.prepare");
|
||||
|
||||
private final OptimizeImportsProcessor myOptimizeImportsProcessor;
|
||||
private final ReformatCodeProcessor myReformatCodeProcessor;
|
||||
|
||||
@@ -28,11 +28,13 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
|
||||
public static final String COMMAND_NAME = CodeInsightBundle.message("process.reformat.code");
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.ReformatCodeProcessor");
|
||||
|
||||
private final TextRange myRange;
|
||||
private static final String PROGRESS_TEXT = CodeInsightBundle.message("reformat.progress.common.text");
|
||||
private static final String COMMAND_NAME = CodeInsightBundle.message("process.reformat.code");
|
||||
|
||||
public ReformatCodeProcessor(Project project) {
|
||||
super(project, COMMAND_NAME, PROGRESS_TEXT);
|
||||
|
||||
@@ -1086,13 +1086,13 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
assert myHidden;
|
||||
assert !myDisposed : disposeTrace;
|
||||
|
||||
hideAutopopupHint();
|
||||
|
||||
Disposer.dispose(myProcessIcon);
|
||||
Disposer.dispose(myHintAlarm);
|
||||
|
||||
myDisposed = true;
|
||||
disposeTrace = DebugUtil.currentStackTrace();
|
||||
|
||||
hideAutopopupHint();
|
||||
}
|
||||
|
||||
private int doSelectMostPreferableItem(List<LookupElement> items) {
|
||||
@@ -1155,7 +1155,13 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
if (myAutopopupHint == null) {
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(hintComponent);
|
||||
myAutopopupHint = new LightweightHint(panel);
|
||||
myAutopopupHint = new LightweightHint(panel) {
|
||||
@Override
|
||||
public void hide() {
|
||||
hideLookup(true);
|
||||
super.hide();
|
||||
}
|
||||
};
|
||||
myAutopopupHint.setForceShowAsPopup(true);
|
||||
hintManager.showEditorHint(myAutopopupHint, editor, new Point(bestPoint),
|
||||
HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.UPDATE_BY_SCROLLING, 0, false, hintHint);
|
||||
@@ -1187,6 +1193,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
c.gridy = i;
|
||||
c.ipadx = itemTextPadding;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
|
||||
|
||||
{
|
||||
@@ -1239,7 +1246,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
if (items.size() > maxAutopopupItems) {
|
||||
final String ctrlSpace = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION));
|
||||
if (StringUtil.isNotEmpty(ctrlSpace)) {
|
||||
final String moreText = ctrlSpace + " for more";
|
||||
final String moreText = ctrlSpace + " for more ";
|
||||
final JLabel moreLabel = new JLabel(moreText);
|
||||
moreLabel.setFont(moreLabel.getFont().deriveFont(Font.PLAIN, editorFont.getSize()));
|
||||
ad.add(moreLabel, BorderLayout.WEST);
|
||||
@@ -1249,7 +1256,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
final String tab = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_REPLACE));
|
||||
if (StringUtil.isNotEmpty(tab)) {
|
||||
final String enter = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM));
|
||||
String message = tab + (isFocused() ? ", " + enter : "") + " for the first item";
|
||||
String message = " " + tab + (isFocused() ? ", " + enter : "") + " for the first item";
|
||||
final JLabel fstLabel = new JLabel(message);
|
||||
fstLabel.setFont(fstLabel.getFont().deriveFont(Font.PLAIN, editorFont.getSize()));
|
||||
ad.add(fstLabel, BorderLayout.EAST);
|
||||
|
||||
@@ -21,9 +21,10 @@ package com.intellij.find;
|
||||
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.find.impl.FindManagerImpl;
|
||||
import com.intellij.find.impl.LiveOccurrence;
|
||||
import com.intellij.find.impl.LivePreview;
|
||||
import com.intellij.find.impl.LivePreviewControllerBase;
|
||||
import com.intellij.find.impl.livePreview.LiveOccurrence;
|
||||
import com.intellij.find.impl.livePreview.LivePreview;
|
||||
import com.intellij.find.impl.livePreview.LivePreviewControllerBase;
|
||||
import com.intellij.find.impl.livePreview.SearchResults;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -38,7 +39,6 @@ import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -69,8 +69,8 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class EditorSearchComponent extends JPanel implements DataProvider, LivePreview.CursorListener, SelectionListener {
|
||||
private static final int MATCHES_LIMIT = 100;
|
||||
public class EditorSearchComponent extends JPanel implements DataProvider, SelectionListener, SearchResults.SearchResultsListener {
|
||||
private static final int MATCHES_LIMIT = 10000;
|
||||
private final JLabel myMatchInfoLabel;
|
||||
private final LinkLabel myClickToHighlightLabel;
|
||||
private final Project myProject;
|
||||
@@ -95,51 +95,14 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
private final JCheckBox myCbInComments;
|
||||
private final JCheckBox myCbInLiterals;
|
||||
|
||||
private final LivePreviewControllerBase myLivePreviewController = new LivePreviewControllerBase() {
|
||||
@Override
|
||||
public void getFocusBack() {
|
||||
mySearchField.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor getEditor(Ref<Boolean> needToUpdate) {
|
||||
needToUpdate.set(true);
|
||||
return myEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void searchEndsWith(int count) {
|
||||
if (count <= getMatchesLimit()) {
|
||||
myClickToHighlightLabel.setVisible(false);
|
||||
|
||||
if (count > 0) {
|
||||
setRegularBackground();
|
||||
if (count > 1) {
|
||||
myMatchInfoLabel.setText(count + " matches");
|
||||
}
|
||||
else {
|
||||
myMatchInfoLabel.setText("1 match");
|
||||
}
|
||||
}
|
||||
else {
|
||||
setNotFoundBackground();
|
||||
myMatchInfoLabel.setText("No matches");
|
||||
}
|
||||
}
|
||||
else {
|
||||
setRegularBackground();
|
||||
myMatchInfoLabel.setText("More than 100 matches");
|
||||
myClickToHighlightLabel.setVisible(true);
|
||||
boldMatchInfo();
|
||||
}
|
||||
}
|
||||
};
|
||||
private final LivePreviewControllerBase myLivePreviewController;
|
||||
private final LivePreview myLivePreview;
|
||||
|
||||
|
||||
private boolean myIsReplace;
|
||||
private boolean myListeningSelection = false;
|
||||
private boolean myToChangeSelection = true;
|
||||
private SearchResults mySearchResults;
|
||||
|
||||
@Nullable
|
||||
public Object getData(@NonNls final String dataId) {
|
||||
@@ -153,12 +116,71 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
this(e, p, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void searchResultsUpdated(SearchResults sr) {
|
||||
int count = sr.getActualFound();
|
||||
if (mySearchField.getText().isEmpty()) {
|
||||
nothingToSearchFor();
|
||||
return;
|
||||
}
|
||||
|
||||
if (count <= mySearchResults.getMatchesLimit()) {
|
||||
myClickToHighlightLabel.setVisible(false);
|
||||
|
||||
if (count > 0) {
|
||||
setRegularBackground();
|
||||
if (count > 1) {
|
||||
myMatchInfoLabel.setText(count + " matches");
|
||||
}
|
||||
else {
|
||||
myMatchInfoLabel.setText("1 match");
|
||||
}
|
||||
}
|
||||
else {
|
||||
setNotFoundBackground();
|
||||
myMatchInfoLabel.setText("No matches");
|
||||
}
|
||||
}
|
||||
else {
|
||||
setRegularBackground();
|
||||
myMatchInfoLabel.setText("More than " + mySearchResults.getMatchesLimit() + " matches");
|
||||
myClickToHighlightLabel.setVisible(true);
|
||||
boldMatchInfo();
|
||||
}
|
||||
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cursorMoved() {
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
private void updateSelection() {
|
||||
if (myToChangeSelection && (mySelectionOnly == null || !mySelectionOnly.isSelected())) {
|
||||
LiveOccurrence cursor = mySearchResults.getCursor();
|
||||
if (cursor != null) {
|
||||
TextRange range = cursor.getPrimaryRange();
|
||||
myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
|
||||
|
||||
myEditor.getCaretModel().moveToOffset(range.getEndOffset());
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
|
||||
myEditor.getCaretModel().moveToOffset(range.getStartOffset());
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
myToChangeSelection = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editorChanged(SearchResults sr, Editor oldEditor) { }
|
||||
|
||||
public EditorSearchComponent(final Editor editor, final Project project, boolean isReplace) {
|
||||
super(new BorderLayout(0, 0));
|
||||
|
||||
myIsReplace = isReplace;
|
||||
|
||||
setMatchesLimit(MATCHES_LIMIT);
|
||||
|
||||
GRADIENT_C1 = getBackground();
|
||||
GRADIENT_C2 = new Color(Math.max(0, GRADIENT_C1.getRed() - 0x18), Math.max(0, GRADIENT_C1.getGreen() - 0x18), Math.max(0, GRADIENT_C1.getBlue() - 0x18));
|
||||
@@ -166,9 +188,18 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
myProject = project;
|
||||
myEditor = editor;
|
||||
|
||||
myLivePreview = new LivePreview(myEditor.getProject(), 0);
|
||||
myLivePreview.addCursorListener(this);
|
||||
myLivePreview.setDelegate(myLivePreviewController);
|
||||
mySearchResults = new SearchResults(myEditor);
|
||||
myLivePreview = new LivePreview(mySearchResults);
|
||||
|
||||
myLivePreviewController = new LivePreviewControllerBase(mySearchResults, myLivePreview) {
|
||||
@Override
|
||||
public void getFocusBack() {
|
||||
mySearchField.requestFocus();
|
||||
}
|
||||
};
|
||||
mySearchResults.addListener(this);
|
||||
setMatchesLimit(MATCHES_LIMIT);
|
||||
|
||||
|
||||
JPanel leadPanel = createLeadPane();
|
||||
add(leadPanel, BorderLayout.WEST);
|
||||
@@ -338,7 +369,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
}
|
||||
|
||||
private void setMatchesLimit(int value) {
|
||||
myLivePreviewController.setMatchesLimit(value);
|
||||
mySearchResults.setMatchesLimit(value);
|
||||
}
|
||||
|
||||
private void configureReplacementPane() {
|
||||
@@ -483,24 +514,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cursorMoved() {
|
||||
if (myToChangeSelection && (mySelectionOnly == null || !mySelectionOnly.isSelected())) {
|
||||
LiveOccurrence cursor = myLivePreview.getCursor();
|
||||
if (cursor != null) {
|
||||
TextRange range = cursor.getPrimaryRange();
|
||||
myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
|
||||
|
||||
myEditor.getCaretModel().moveToOffset(range.getEndOffset());
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
|
||||
myEditor.getCaretModel().moveToOffset(range.getStartOffset());
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
myToChangeSelection = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectionChanged(SelectionEvent e) {
|
||||
updateResults(true);
|
||||
@@ -509,9 +522,9 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
public void moveCursor(boolean forwardOrBackward) {
|
||||
myToChangeSelection = true;
|
||||
if (forwardOrBackward) {
|
||||
myLivePreview.nextOccurrence();
|
||||
mySearchResults.nextOccurrence();
|
||||
} else {
|
||||
myLivePreview.prevOccurrence();
|
||||
mySearchResults.prevOccurrence();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,7 +568,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
myEditor.getDocument().addDocumentListener(myDocumentListener);
|
||||
|
||||
if (myLivePreview != null) {
|
||||
myLivePreview.update();
|
||||
myLivePreviewController.updateInBackground(mySearchResults.getFindModel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,12 +589,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
myMatchInfoLabel.setFont(myMatchInfoLabel.getFont().deriveFont(Font.PLAIN));
|
||||
final String text = mySearchField.getText();
|
||||
if (text.length() == 0) {
|
||||
setRegularBackground();
|
||||
myMatchInfoLabel.setText("");
|
||||
myClickToHighlightLabel.setVisible(false);
|
||||
if (myLivePreview != null) {
|
||||
myLivePreview.cleanUp();
|
||||
}
|
||||
nothingToSearchFor();
|
||||
}
|
||||
else {
|
||||
final FindModel model = new FindModel();
|
||||
@@ -628,9 +636,17 @@ public class EditorSearchComponent extends JPanel implements DataProvider, LiveP
|
||||
model.setPreserveCase(myPreserveCase.isEnabled() && myPreserveCase.isSelected());
|
||||
}
|
||||
myToChangeSelection = allowedToChangedEditorSelection;
|
||||
myLivePreviewController.setFindModel(model);
|
||||
myLivePreview.update();
|
||||
|
||||
myLivePreviewController.updateInBackground(model);
|
||||
}
|
||||
}
|
||||
|
||||
private void nothingToSearchFor() {
|
||||
setRegularBackground();
|
||||
myMatchInfoLabel.setText("");
|
||||
myClickToHighlightLabel.setVisible(false);
|
||||
if (myLivePreview != null) {
|
||||
myLivePreview.cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -410,6 +410,15 @@ public class FindUtil {
|
||||
}
|
||||
|
||||
public static boolean replace(Project project, Editor editor, int offset, FindModel model) {
|
||||
return replace(project, editor, offset, model, new ReplaceDelegate() {
|
||||
@Override
|
||||
public boolean shouldReplace(TextRange range, String replace) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean replace(Project project, Editor editor, int offset, FindModel model, ReplaceDelegate delegate) {
|
||||
Document document = editor.getDocument();
|
||||
|
||||
if (!FileDocumentManager.getInstance().requestWriting(document, project)) {
|
||||
@@ -423,7 +432,7 @@ public class FindUtil {
|
||||
((DocumentEx) document).setInBulkUpdate(true);
|
||||
}
|
||||
try {
|
||||
toPrompt = doReplace(project, editor, model, document, offset, toPrompt);
|
||||
toPrompt = doReplace(project, editor, model, document, offset, toPrompt, delegate);
|
||||
}
|
||||
catch (ReadOnlyFragmentModificationException e) {
|
||||
EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(document).handle(e);
|
||||
@@ -438,7 +447,8 @@ public class FindUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean doReplace(Project project, Editor editor, FindModel model, final Document document, int caretOffset, boolean toPrompt) {
|
||||
private static boolean doReplace(Project project, Editor editor, FindModel model, final Document document, int caretOffset,
|
||||
boolean toPrompt, ReplaceDelegate delegate) {
|
||||
FindManager findManager = FindManager.getInstance(project);
|
||||
model = (FindModel)model.clone();
|
||||
int occurrences = 0;
|
||||
@@ -517,7 +527,11 @@ public class FindUtil {
|
||||
TextRange range = pair.getFirst();
|
||||
String replace = pair.getSecond();
|
||||
newText.append(text, offsetBefore, range.getStartOffset()); //before change
|
||||
newText.append(replace);
|
||||
if (delegate.shouldReplace(range, replace)) {
|
||||
newText.append(replace);
|
||||
} else {
|
||||
newText.append(text.subSequence(range.getStartOffset(), range.getEndOffset()));
|
||||
}
|
||||
offsetBefore = range.getEndOffset();
|
||||
if (offsetBefore < caretOffset) {
|
||||
caretOffset += replace.length() - range.getLength();
|
||||
@@ -761,4 +775,8 @@ public class FindUtil {
|
||||
editor.getCaretModel().moveToLogicalPosition(pos);
|
||||
editor.getScrollingModel().scrollToCaret(scrollType);
|
||||
}
|
||||
|
||||
public interface ReplaceDelegate {
|
||||
boolean shouldReplace(TextRange range, String replace) ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.intellij.find.impl;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.find.FindBundle;
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindSettings;
|
||||
import com.intellij.ide.util.scopeChooser.ScopeChooserCombo;
|
||||
@@ -108,9 +107,6 @@ class FindDialog extends DialogWrapper {
|
||||
private JRadioButton myRbCustomScope;
|
||||
private ScopeChooserCombo myScopeCombo;
|
||||
|
||||
private LivePreviewController myLivePreviewController;
|
||||
|
||||
|
||||
public FindDialog(Project project, FindModel model, Runnable myOkHandler){
|
||||
super(project, true);
|
||||
myProject = project;
|
||||
@@ -139,7 +135,7 @@ class FindDialog extends DialogWrapper {
|
||||
setOKButtonIcon(IconLoader.getIcon("/actions/find.png"));
|
||||
init();
|
||||
initByModel();
|
||||
myLivePreviewController = new LivePreviewController(this, new LivePreview(myProject), getContentPane());
|
||||
//myLivePreviewController = new LivePreviewController(this, new LivePreview(myProject), getContentPane());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,9 +144,9 @@ class FindDialog extends DialogWrapper {
|
||||
e.getKey().removeDocumentListener(e.getValue());
|
||||
}
|
||||
myComboBoxListeners.clear();
|
||||
if (myLivePreviewController != null) {
|
||||
myLivePreviewController.cleanUp();
|
||||
}
|
||||
//if (myLivePreviewController != null) {
|
||||
// myLivePreviewController.cleanUp();
|
||||
//}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,570 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.find.impl;
|
||||
|
||||
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.ide.IdeTooltipManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.editor.VisualPosition;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.event.VisibleAreaEvent;
|
||||
import com.intellij.openapi.editor.event.VisibleAreaListener;
|
||||
import com.intellij.openapi.editor.markup.CustomHighlighterRenderer;
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
import com.intellij.openapi.ui.popup.BalloonBuilder;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.PositionTracker;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class LivePreview extends DocumentAdapter implements ReplacementView.Delegate {
|
||||
|
||||
private final Collection<RangeHighlighter> myHighlighters = new HashSet<RangeHighlighter>();
|
||||
private RangeHighlighter myCursorHighlighter;
|
||||
private final List<VisibleAreaListener> myVisibleAreaListenersToRemove = new ArrayList<VisibleAreaListener>();
|
||||
private boolean myShouldStop;
|
||||
|
||||
@Override
|
||||
public void performReplacement(LiveOccurrence occurrence, String replacement) {
|
||||
if (myDelegate != null) {
|
||||
final TextRange textRange = myDelegate.performReplace(occurrence, replacement, myEditor);
|
||||
if (textRange != null) {
|
||||
updateInBackground();
|
||||
setContinuation(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mySearchResults != null) {
|
||||
LiveOccurrence nearest = null;
|
||||
int minDist = Integer.MAX_VALUE;
|
||||
for (LiveOccurrence o : mySearchResults) {
|
||||
if (nearest == null) {
|
||||
nearest = o;
|
||||
}
|
||||
int dist = Math.abs(o.getPrimaryRange().getStartOffset() - textRange.getStartOffset());
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
nearest = o;
|
||||
}
|
||||
}
|
||||
if (nearest != null) {
|
||||
moveCursorTo(nearest);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
myDelegate.getFocusBack();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performReplaceAll() {
|
||||
myDelegate.performReplaceAll(myEditor);
|
||||
}
|
||||
|
||||
public boolean hasMatches() {
|
||||
return mySearchResults != null && !mySearchResults.isEmpty();
|
||||
}
|
||||
|
||||
public LiveOccurrence getCursor() {
|
||||
return myCursor;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public Editor getEditor() {
|
||||
return myEditor;
|
||||
}
|
||||
|
||||
public interface CursorListener {
|
||||
void cursorMoved();
|
||||
}
|
||||
|
||||
private final List<CursorListener> myListeners = new ArrayList<CursorListener>();
|
||||
|
||||
public void addCursorListener(CursorListener listener) {
|
||||
myListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeCursorListener(CursorListener listener) {
|
||||
myListeners.remove(listener);
|
||||
}
|
||||
|
||||
public interface Delegate {
|
||||
@NotNull
|
||||
List<LiveOccurrence> performSearchInBackgroundInReadAction(Editor editor);
|
||||
|
||||
@Nullable
|
||||
String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence);
|
||||
|
||||
TextRange performReplace(LiveOccurrence occurrence, String replacement, Editor editor);
|
||||
|
||||
void performReplaceAll(Editor e);
|
||||
|
||||
void getFocusBack();
|
||||
|
||||
Editor getEditor(Ref<Boolean> needToUpdate);
|
||||
}
|
||||
|
||||
private static final int USER_ACTIVITY_TRIGGERING_DELAY = 300;
|
||||
|
||||
private static final TextAttributes OTHER_TARGETS_ATTRIBUTES = new TextAttributes(Color.BLACK, Color.GREEN, null, null, 0);
|
||||
private static final TextAttributes MAIN_TARGET_ATTRIBUTES = new TextAttributes(Color.BLACK, Color.YELLOW, null, null, 0);
|
||||
|
||||
private final Alarm myLivePreviewAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
|
||||
|
||||
private final Project myProject;
|
||||
private Editor myEditor;
|
||||
|
||||
private Delegate myDelegate;
|
||||
|
||||
private LiveOccurrence myCursor;
|
||||
|
||||
private Runnable myContinuation;
|
||||
|
||||
private int myUserActivityDelay = USER_ACTIVITY_TRIGGERING_DELAY;
|
||||
|
||||
public Runnable getContinuation() {
|
||||
return myContinuation;
|
||||
}
|
||||
|
||||
public void setContinuation(Runnable continuation) {
|
||||
myContinuation = continuation;
|
||||
}
|
||||
|
||||
public List<LiveOccurrence> getSearchResults() {
|
||||
return mySearchResults;
|
||||
}
|
||||
|
||||
private List<LiveOccurrence> mySearchResults;
|
||||
|
||||
private Balloon myReplacementBalloon;
|
||||
|
||||
public LivePreview(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public LivePreview(Project project, int delay) {
|
||||
this(project);
|
||||
myUserActivityDelay = delay;
|
||||
}
|
||||
|
||||
public Delegate getDelegate() {
|
||||
return myDelegate;
|
||||
}
|
||||
|
||||
public void setDelegate(Delegate delegate) {
|
||||
myDelegate = delegate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Editor updateEditorReference() {
|
||||
if (myProject == null) return null;
|
||||
Ref<Boolean> needToUpdate = new Ref<Boolean>();
|
||||
Editor result = myDelegate.getEditor(needToUpdate);
|
||||
if (!needToUpdate.isNull() && needToUpdate.get()) {
|
||||
setEditor(result);
|
||||
}
|
||||
return myEditor;
|
||||
}
|
||||
|
||||
private void setEditor(Editor editor) {
|
||||
if (editor != myEditor) {
|
||||
doInternalCleanUp();
|
||||
}
|
||||
if (myEditor != null) {
|
||||
myEditor.getDocument().removeDocumentListener(this);
|
||||
}
|
||||
myEditor = editor;
|
||||
if (myEditor != null) {
|
||||
myEditor.getDocument().addDocumentListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent e) {
|
||||
doInternalCleanUp();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
myShouldStop = false;
|
||||
myLivePreviewAlarm.cancelAllRequests();
|
||||
if (updateEditorReference() != null) {
|
||||
Runnable request = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateInBackground();
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
request.run();
|
||||
} else {
|
||||
myLivePreviewAlarm.addRequest(request, myUserActivityDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
myShouldStop = true;
|
||||
myLivePreviewAlarm.cancelAllRequests();
|
||||
doInternalCleanUp();
|
||||
}
|
||||
|
||||
private void doInternalCleanUp() {
|
||||
if (myReplacementBalloon != null) {
|
||||
myReplacementBalloon.hide();
|
||||
}
|
||||
if (myEditor != null) {
|
||||
|
||||
for (VisibleAreaListener visibleAreaListener : myVisibleAreaListenersToRemove) {
|
||||
myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
|
||||
}
|
||||
myVisibleAreaListenersToRemove.clear();
|
||||
for (RangeHighlighter h : myHighlighters) {
|
||||
HighlightManager.getInstance(myProject).removeSegmentHighlighter(myEditor, h);
|
||||
}
|
||||
if (myCursorHighlighter != null) {
|
||||
HighlightManager.getInstance(myProject).removeSegmentHighlighter(myEditor, myCursorHighlighter);
|
||||
myCursorHighlighter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateInBackground() {
|
||||
if (myDelegate == null) return;
|
||||
final TextRange oldCursorRange = myCursor != null ? myCursor.getPrimaryRange() : null;
|
||||
mySearchResults = performSearchInBackground();
|
||||
Collections.sort(mySearchResults, new Comparator<LiveOccurrence>() {
|
||||
@Override
|
||||
public int compare(LiveOccurrence liveOccurrence, LiveOccurrence liveOccurence1) {
|
||||
return liveOccurrence.getPrimaryRange().getStartOffset() - liveOccurence1.getPrimaryRange().getStartOffset();
|
||||
}
|
||||
});
|
||||
if (mySearchResults != null) {
|
||||
Runnable highlightUsagesBlock = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doInternalCleanUp();
|
||||
highlightUsages(oldCursorRange);
|
||||
if (myContinuation != null) {
|
||||
myContinuation.run();
|
||||
myContinuation = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
highlightUsagesBlock.run();
|
||||
} else {
|
||||
ApplicationManager.getApplication().invokeLater(highlightUsagesBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<LiveOccurrence> performSearchInBackground() {
|
||||
final AtomicReference<List<LiveOccurrence>> occurrences = new AtomicReference<List<LiveOccurrence>>();
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
occurrences.set(myDelegate.performSearchInBackgroundInReadAction(myEditor));
|
||||
}
|
||||
});
|
||||
return occurrences.get();
|
||||
}
|
||||
|
||||
private void highlightUsages(TextRange oldCursorRange) {
|
||||
if (myEditor == null || myShouldStop) return;
|
||||
for (LiveOccurrence o : mySearchResults) {
|
||||
for (TextRange textRange : o.getSecondaryRanges()) {
|
||||
highlightRange(textRange, OTHER_TARGETS_ATTRIBUTES, myHighlighters);
|
||||
}
|
||||
highlightRange(o.getPrimaryRange(), MAIN_TARGET_ATTRIBUTES, myHighlighters);
|
||||
}
|
||||
|
||||
if (!tryToRepairOldCursor(oldCursorRange)) {
|
||||
LiveOccurrence afterCaret = firstOccurrenceAfterCaret();
|
||||
if (afterCaret != null) {
|
||||
setCursor(afterCaret);
|
||||
} else {
|
||||
LiveOccurrence occurrence = firstVisibleOccurrence();
|
||||
if (occurrence != null) {
|
||||
setCursor(occurrence);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence firstVisibleOccurrence() {
|
||||
int offset = Integer.MAX_VALUE;
|
||||
LiveOccurrence firstOccurrence = null;
|
||||
LiveOccurrence firstVisibleOccurrence = null;
|
||||
for (LiveOccurrence o : mySearchResults) {
|
||||
if (insideVisibleArea(myEditor, o.getPrimaryRange())) {
|
||||
if (firstVisibleOccurrence == null || o.getPrimaryRange().getStartOffset() < firstVisibleOccurrence.getPrimaryRange().getStartOffset()) {
|
||||
firstVisibleOccurrence = o;
|
||||
}
|
||||
}
|
||||
if (o.getPrimaryRange().getStartOffset() < offset) {
|
||||
offset = o.getPrimaryRange().getStartOffset();
|
||||
firstOccurrence = o;
|
||||
}
|
||||
}
|
||||
return firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence firstOccurrenceAfterCaret() {
|
||||
LiveOccurrence afterCaret = null;
|
||||
int caret = myEditor.getCaretModel().getOffset();
|
||||
for (LiveOccurrence occurrence : mySearchResults) {
|
||||
if (occurrence.getPrimaryRange().getStartOffset() >= caret) {
|
||||
if (afterCaret == null || occurrence.getPrimaryRange().getStartOffset() < afterCaret.getPrimaryRange().getStartOffset() ) {
|
||||
afterCaret = occurrence;
|
||||
}
|
||||
}
|
||||
}
|
||||
return afterCaret;
|
||||
}
|
||||
|
||||
private boolean tryToRepairOldCursor(TextRange oldCursorRange) {
|
||||
if (oldCursorRange == null) return false;
|
||||
LiveOccurrence mayBeOldCursor = null;
|
||||
for (LiveOccurrence searchResult : mySearchResults) {
|
||||
if (searchResult.getPrimaryRange().intersects(oldCursorRange)) {
|
||||
mayBeOldCursor = searchResult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mayBeOldCursor != null && insideVisibleArea(myEditor, mayBeOldCursor.getPrimaryRange())) {
|
||||
setCursor(mayBeOldCursor);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence prevOccurrence(LiveOccurrence o) {
|
||||
if (mySearchResults == null) return null;
|
||||
for (int i = 0; i < mySearchResults.size(); ++i) {
|
||||
if (o == mySearchResults.get(i)) {
|
||||
if (i > 0) {
|
||||
return mySearchResults.get(i-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence nextOccurrence(LiveOccurrence o) {
|
||||
if (mySearchResults == null) return null;
|
||||
boolean found = false;
|
||||
for (LiveOccurrence occurrence : mySearchResults) {
|
||||
if (found) {
|
||||
return occurrence;
|
||||
}
|
||||
if (o == occurrence) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void prevOccurrence() {
|
||||
LiveOccurrence prev = prevOccurrence(myCursor);
|
||||
if (prev == null && !mySearchResults.isEmpty()) {
|
||||
prev = mySearchResults.get(mySearchResults.size()-1);
|
||||
}
|
||||
moveCursorTo(prev);
|
||||
}
|
||||
|
||||
public void nextOccurrence() {
|
||||
LiveOccurrence next = nextOccurrence(myCursor);
|
||||
if (next == null && !mySearchResults.isEmpty()) {
|
||||
next = mySearchResults.get(0);
|
||||
}
|
||||
moveCursorTo(next);
|
||||
}
|
||||
|
||||
public void moveCursorTo(LiveOccurrence next) {
|
||||
if (next != null) {
|
||||
setCursor(next);
|
||||
} else {
|
||||
showReplacementPreview();
|
||||
}
|
||||
}
|
||||
|
||||
private void setCursor(LiveOccurrence liveOccurrence) {
|
||||
hideBalloon();
|
||||
boolean toNotify = myCursor == null || !myCursor.equals(liveOccurrence);
|
||||
|
||||
myCursor = liveOccurrence;
|
||||
|
||||
if (myCursorHighlighter != null) {
|
||||
HighlightManager.getInstance(myProject).removeSegmentHighlighter(myEditor, myCursorHighlighter);
|
||||
myCursorHighlighter = null;
|
||||
}
|
||||
if (myCursor != null) {
|
||||
ArrayList<RangeHighlighter> dummy = new ArrayList<RangeHighlighter>();
|
||||
highlightRange(myCursor.getPrimaryRange(), new TextAttributes(null, null, null, null, 0), dummy);
|
||||
if (!dummy.isEmpty()) {
|
||||
myCursorHighlighter = dummy.get(0);
|
||||
myCursorHighlighter.setCustomRenderer(new MyCustomCursorRenderer());
|
||||
}
|
||||
|
||||
if (!insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
|
||||
myEditor.getScrollingModel().scrollTo(myEditor.offsetToLogicalPosition(myCursor.getPrimaryRange().getStartOffset()),
|
||||
ScrollType.CENTER);
|
||||
myEditor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showReplacementPreview();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showReplacementPreview();
|
||||
}
|
||||
}
|
||||
if (toNotify) {
|
||||
for (CursorListener l : myListeners) {
|
||||
if (l!= null) {
|
||||
l.cursorMoved();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showReplacementPreview() {
|
||||
hideBalloon();
|
||||
if (myDelegate != null && myCursor != null) {
|
||||
String replacementPreviewText = myDelegate.getReplacementPreviewText(myEditor, myCursor);
|
||||
if (replacementPreviewText != null) {
|
||||
|
||||
//JLabel balloonContent = new JLabel(replacementPreviewText);
|
||||
//balloonContent.setForeground(Color.WHITE);
|
||||
|
||||
ReplacementView replacementView = new ReplacementView(replacementPreviewText, myCursor);
|
||||
replacementView.setDelegate(this);
|
||||
|
||||
BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(replacementView);
|
||||
balloonBuilder.setFadeoutTime(0);
|
||||
balloonBuilder.setFillColor(IdeTooltipManager.GRAPHITE_COLOR);
|
||||
balloonBuilder.setAnimationCycle(0);
|
||||
balloonBuilder.setHideOnClickOutside(false);
|
||||
balloonBuilder.setHideOnKeyOutside(false);
|
||||
balloonBuilder.setHideOnAction(false);
|
||||
balloonBuilder.setCloseButtonEnabled(true);
|
||||
myReplacementBalloon = balloonBuilder.createBalloon();
|
||||
final int startOffset = myCursor.getPrimaryRange().getStartOffset();
|
||||
final int endOffset = myCursor.getPrimaryRange().getEndOffset();
|
||||
|
||||
myReplacementBalloon.show(new PositionTracker<Balloon>(myEditor.getContentComponent()) {
|
||||
@Override
|
||||
public RelativePoint recalculateLocation(final Balloon object) {
|
||||
Point startPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(startOffset));
|
||||
Point endPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(endOffset));
|
||||
Point point = new Point((startPoint.x + endPoint.x)/2, startPoint.y);
|
||||
if (!insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
object.hide();
|
||||
}
|
||||
});
|
||||
|
||||
VisibleAreaListener visibleAreaListener = new VisibleAreaListener() {
|
||||
@Override
|
||||
public void visibleAreaChanged(VisibleAreaEvent e) {
|
||||
if (insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
|
||||
showReplacementPreview();
|
||||
final VisibleAreaListener visibleAreaListener = this;
|
||||
myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
|
||||
myVisibleAreaListenersToRemove.remove(visibleAreaListener);
|
||||
}
|
||||
}
|
||||
};
|
||||
myEditor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
|
||||
myVisibleAreaListenersToRemove.add(visibleAreaListener);
|
||||
|
||||
}
|
||||
return new RelativePoint(myEditor.getContentComponent(), point);
|
||||
}
|
||||
}, Balloon.Position.above);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideBalloon() {
|
||||
if (myReplacementBalloon != null) {
|
||||
myReplacementBalloon.hide();
|
||||
myReplacementBalloon = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void highlightRange(TextRange textRange, TextAttributes attributes, Collection<RangeHighlighter> highlighters) {
|
||||
HighlightManager highlightManager = HighlightManager.getInstance(myProject);
|
||||
if (highlightManager != null) {
|
||||
highlightManager.addRangeHighlight(myEditor,
|
||||
textRange.getStartOffset(), textRange.getEndOffset(),
|
||||
attributes, false, highlighters);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean insideVisibleArea(Editor e, TextRange r) {
|
||||
Rectangle visibleArea = e.getScrollingModel().getVisibleArea();
|
||||
Point point = e.logicalPositionToXY(e.offsetToLogicalPosition(r.getStartOffset()));
|
||||
|
||||
return visibleArea.contains(point);
|
||||
}
|
||||
|
||||
private static class MyCustomCursorRenderer implements CustomHighlighterRenderer {
|
||||
@Override
|
||||
public void paint(Editor editor, RangeHighlighter highlighter, Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
VisualPosition startVp = editor.offsetToVisualPosition(highlighter.getStartOffset());
|
||||
VisualPosition endVp = editor.offsetToVisualPosition(highlighter.getEndOffset());
|
||||
Point start = editor.visualPositionToXY(startVp);
|
||||
Point end = editor.visualPositionToXY(endVp);
|
||||
g2d.setColor(new Color(50, 50, 50));
|
||||
g2d.translate(0, start.y - 4);
|
||||
Color c1 = new Color(220, 200, 130);
|
||||
Color c2 = new Color(220, 170, 30);
|
||||
UIUtil.drawSearchMatch(g2d, start.x- 1, end.x+ 1, editor.getLineHeight() +2* 4, c1, c2);
|
||||
g2d.translate(0, -start.y + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package com.intellij.find.impl;
|
||||
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.UserActivityListener;
|
||||
import com.intellij.ui.UserActivityWatcher;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowFocusListener;
|
||||
import java.util.List;
|
||||
|
||||
public class LivePreviewController implements LivePreview.Delegate, UserActivityListener {
|
||||
|
||||
|
||||
private final FindDialog myFindDialog;
|
||||
private final LivePreview myLivePreview;
|
||||
private final UserActivityWatcher myWatcher = new MomentoUserActivityWatcher();
|
||||
|
||||
LivePreviewControllerBase myDelegate = new LivePreviewControllerBase();
|
||||
|
||||
private void updateDelegatesFindModel() {
|
||||
FindModel currentModel = myFindDialog.getCurrentModel();
|
||||
myDelegate.setFindModel(currentModel);
|
||||
}
|
||||
|
||||
public LivePreviewController(FindDialog findDialog, LivePreview livePreview, Component toWatch) {
|
||||
myFindDialog = findDialog;
|
||||
myLivePreview = livePreview;
|
||||
myLivePreview.setDelegate(this);
|
||||
myWatcher.register(toWatch);
|
||||
myWatcher.addUserActivityListener(this);
|
||||
myFindDialog.getWindow().addWindowFocusListener(new WindowFocusListener() {
|
||||
@Override
|
||||
public void windowGainedFocus(WindowEvent windowEvent) {
|
||||
myLivePreview.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowLostFocus(WindowEvent windowEvent) {
|
||||
}
|
||||
});
|
||||
|
||||
JComponent contentPane = (JComponent)findDialog.getContentPane();
|
||||
new AnAction() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myLivePreview.nextOccurrence();
|
||||
}
|
||||
}.registerCustomShortcutSet(KeyEvent.VK_F3, 0, contentPane);
|
||||
|
||||
new AnAction() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myLivePreview.prevOccurrence();
|
||||
}
|
||||
}.registerCustomShortcutSet(KeyEvent.VK_F3, KeyEvent.SHIFT_MASK, contentPane);
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
myWatcher.removeUserActivityListener(this);
|
||||
myLivePreview.cleanUp();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<LiveOccurrence> performSearchInBackgroundInReadAction(Editor editor) {
|
||||
updateDelegatesFindModel();
|
||||
return myDelegate.performSearchInBackgroundInReadAction(editor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performReplaceAll(Editor e) {
|
||||
updateDelegatesFindModel();
|
||||
myDelegate.performReplaceAll(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getFocusBack() {
|
||||
myFindDialog.getContentPane().requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor getEditor(Ref<Boolean> needToUpdate) {
|
||||
Editor result = null;
|
||||
FileEditorManagerEx instanceEx = FileEditorManagerEx.getInstanceEx(myLivePreview.getProject());
|
||||
if (instanceEx != null) {
|
||||
VirtualFile currentFile = instanceEx.getCurrentFile();
|
||||
if (currentFile != null) {
|
||||
FileEditor[] editors = instanceEx.getEditors(currentFile);
|
||||
if (editors.length > 0) {
|
||||
FileEditor fileEditor = editors[0];
|
||||
boolean focusedFound = false;
|
||||
for (FileEditor e : editors) {
|
||||
if (e instanceof TextEditor && ((TextEditor)e).getEditor().getContentComponent().hasFocus()) {
|
||||
fileEditor = e;
|
||||
focusedFound = true;
|
||||
}
|
||||
}
|
||||
needToUpdate.set(true);
|
||||
if (!focusedFound) {
|
||||
for (FileEditor e : editors) {
|
||||
if (e instanceof TextEditor && ((TextEditor)e).getEditor() == myLivePreview.getEditor()) {
|
||||
needToUpdate.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(needToUpdate.get() && fileEditor instanceof TextEditor) {
|
||||
result = ((TextEditor)fileEditor).getEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRange performReplace(final LiveOccurrence occurrence, final String replacement, final Editor editor) {
|
||||
updateDelegatesFindModel();
|
||||
return myDelegate.performReplace(occurrence, replacement, editor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence) {
|
||||
updateDelegatesFindModel();
|
||||
return myDelegate.getReplacementPreviewText(editor, liveOccurrence);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stateChanged() {
|
||||
myLivePreview.update();
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package com.intellij.find.impl;
|
||||
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindResult;
|
||||
import com.intellij.find.FindUtil;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class LivePreviewControllerBase implements LivePreview.Delegate {
|
||||
|
||||
private static final String EMPTY_STRING_DISPLAY_TEXT = "<Empty string>";
|
||||
|
||||
private int myMatchesLimit = 100;
|
||||
|
||||
public int getMatchesLimit() {
|
||||
return myMatchesLimit;
|
||||
}
|
||||
|
||||
public void setMatchesLimit(int matchesLimit) {
|
||||
myMatchesLimit = matchesLimit;
|
||||
}
|
||||
|
||||
private FindModel myFindModel;
|
||||
|
||||
public FindModel getFindModel() {
|
||||
return myFindModel;
|
||||
}
|
||||
|
||||
public void setFindModel(FindModel findModel) {
|
||||
myFindModel = findModel;
|
||||
}
|
||||
|
||||
private static void findResultsToOccurrences(ArrayList<FindResult> results, Collection<LiveOccurrence> occurrences) {
|
||||
for (FindResult r : results) {
|
||||
LiveOccurrence occurrence = new LiveOccurrence();
|
||||
occurrence.setPrimaryRange(r);
|
||||
occurrences.add(occurrence);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<LiveOccurrence> performSearchInBackgroundInReadAction(Editor editor) {
|
||||
ArrayList<LiveOccurrence> occurrences = new ArrayList<LiveOccurrence>();
|
||||
if (myFindModel != null) {
|
||||
|
||||
TextRange r = myFindModel.isGlobal() ? new TextRange(0, Integer.MAX_VALUE) :
|
||||
new TextRange(editor.getSelectionModel().getSelectionStart(),
|
||||
editor.getSelectionModel().getSelectionEnd());
|
||||
if (r.getLength() == 0) {
|
||||
r = new TextRange(0, Integer.MAX_VALUE);
|
||||
}
|
||||
int offset = r.getStartOffset();
|
||||
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
|
||||
final ArrayList<FindResult> results = new ArrayList<FindResult>();
|
||||
|
||||
while (true) {
|
||||
FindManager findManager = FindManager.getInstance(editor.getProject());
|
||||
FindResult result = findManager.findString(editor.getDocument().getCharsSequence(), offset, myFindModel, virtualFile);
|
||||
if (!result.isStringFound()) break;
|
||||
int newOffset = result.getEndOffset();
|
||||
if (offset == newOffset || result.getEndOffset() > r.getEndOffset()) break;
|
||||
offset = newOffset;
|
||||
results.add(result);
|
||||
|
||||
if (results.size() > myMatchesLimit) break;
|
||||
}
|
||||
if (results.size() < myMatchesLimit) {
|
||||
|
||||
findResultsToOccurrences(results, occurrences);
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
searchEndsWith(results.size());
|
||||
}
|
||||
});
|
||||
}
|
||||
return occurrences;
|
||||
}
|
||||
|
||||
protected void searchEndsWith(int size) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence) {
|
||||
String foundString = editor.getDocument().getText(liveOccurrence.getPrimaryRange());
|
||||
String documentText = editor.getDocument().getText();
|
||||
FindModel currentModel = myFindModel;
|
||||
String stringToReplace = null;
|
||||
|
||||
if (currentModel != null) {
|
||||
if (currentModel.isReplaceState()) {
|
||||
FindManager findManager = FindManager.getInstance(editor.getProject());
|
||||
try {
|
||||
stringToReplace = findManager.getStringToReplace(foundString, currentModel,
|
||||
liveOccurrence.getPrimaryRange().getStartOffset(), documentText);
|
||||
}
|
||||
catch (FindManager.MalformedReplacementStringException e) {
|
||||
return null;
|
||||
}
|
||||
if (stringToReplace != null && stringToReplace.isEmpty()) {
|
||||
stringToReplace = EMPTY_STRING_DISPLAY_TEXT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return stringToReplace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRange performReplace(final LiveOccurrence occurrence, final String replacement, final Editor editor) {
|
||||
TextRange range = occurrence.getPrimaryRange();
|
||||
try {
|
||||
return FindUtil.doReplace(editor.getProject(), editor.getDocument(), myFindModel, new FindResultImpl(range.getStartOffset(), range.getEndOffset()),
|
||||
FindManager.getInstance(editor.getProject()).getStringToReplace(editor.getDocument().getText(range), myFindModel), true, new ArrayList<Pair<TextRange, String>>());
|
||||
}
|
||||
catch (FindManager.MalformedReplacementStringException e) {
|
||||
/**/
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performReplaceAll(Editor e) {
|
||||
FindUtil.replace(e.getProject(), e, 0, myFindModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getFocusBack() {}
|
||||
|
||||
@Override
|
||||
public Editor getEditor(Ref<Boolean> needToUpdate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.intellij.find.impl;
|
||||
|
||||
import com.intellij.ide.IdeTooltipManager;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class ReplacementView extends JPanel {
|
||||
|
||||
private String myReplacement;
|
||||
private LiveOccurrence myOccurrence;
|
||||
|
||||
public interface Delegate {
|
||||
void performReplacement(LiveOccurrence occurrence, String replacement);
|
||||
void performReplaceAll();
|
||||
}
|
||||
|
||||
private Delegate delegate;
|
||||
|
||||
public Delegate getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public void setDelegate(Delegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public ReplacementView(final String replacement, final LiveOccurrence occurrence) {
|
||||
myReplacement = replacement;
|
||||
myOccurrence = occurrence;
|
||||
JLabel jLabel = new JLabel(replacement);
|
||||
jLabel.setForeground(Color.WHITE);
|
||||
add(jLabel);
|
||||
JButton replace = new JButton("Replace");
|
||||
replace.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
if (delegate != null) {
|
||||
delegate.performReplacement(occurrence, replacement);
|
||||
}
|
||||
}
|
||||
});
|
||||
replace.setMnemonic('R');
|
||||
add(replace);
|
||||
JButton replaceAllButton = new JButton("Replace all");
|
||||
replaceAllButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
if (delegate != null) {
|
||||
delegate.performReplaceAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
replaceAllButton.setMnemonic('a');
|
||||
add(replaceAllButton);
|
||||
setBackground(IdeTooltipManager.GRAPHITE_COLOR);
|
||||
if (SystemInfo.isMac) {
|
||||
Font f = getFont();
|
||||
setFont(f.deriveFont(f.getStyle(), f.getSize() - 4));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+6
-1
@@ -1,4 +1,4 @@
|
||||
package com.intellij.find.impl;
|
||||
package com.intellij.find.impl.livePreview;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
|
||||
@@ -34,4 +34,9 @@ public class LiveOccurrence {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myPrimaryRange.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.find.impl.livePreview;
|
||||
|
||||
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.ide.IdeTooltipManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.editor.VisualPosition;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.VisibleAreaEvent;
|
||||
import com.intellij.openapi.editor.event.VisibleAreaListener;
|
||||
import com.intellij.openapi.editor.markup.CustomHighlighterRenderer;
|
||||
import com.intellij.openapi.editor.markup.EffectType;
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
import com.intellij.openapi.ui.popup.BalloonBuilder;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.PositionTracker;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
public class LivePreview extends DocumentAdapter implements ReplacementView.Delegate, SearchResults.SearchResultsListener {
|
||||
|
||||
public interface Delegate {
|
||||
|
||||
@Nullable
|
||||
String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence);
|
||||
|
||||
@Nullable
|
||||
TextRange performReplace(LiveOccurrence occurrence, String replacement, Editor editor);
|
||||
|
||||
void performReplaceAll(Editor e);
|
||||
|
||||
void getFocusBack();
|
||||
|
||||
}
|
||||
|
||||
private final Collection<RangeHighlighter> myHighlighters = new HashSet<RangeHighlighter>();
|
||||
|
||||
|
||||
private RangeHighlighter myCursorHighlighter;
|
||||
private final List<VisibleAreaListener> myVisibleAreaListenersToRemove = new ArrayList<VisibleAreaListener>();
|
||||
|
||||
private static final TextAttributes EXCLUDED_TARGET_ATTRIBUTES = new TextAttributes(Color.BLACK, Color.YELLOW,
|
||||
Color.BLACK, EffectType.STRIKEOUT, 0);
|
||||
|
||||
private static final TextAttributes OTHER_TARGETS_ATTRIBUTES = new TextAttributes(Color.BLACK, Color.GREEN, null, null, 0);
|
||||
|
||||
private static final TextAttributes MAIN_TARGET_ATTRIBUTES = new TextAttributes(Color.BLACK, Color.YELLOW, null, null, 0);
|
||||
|
||||
private Delegate myDelegate;
|
||||
|
||||
private SearchResults mySearchResults;
|
||||
|
||||
private Balloon myReplacementBalloon;
|
||||
|
||||
@Override
|
||||
public void performReplacement(LiveOccurrence occurrence, String replacement) {
|
||||
if (myDelegate != null) {
|
||||
myDelegate.performReplace(occurrence, replacement, mySearchResults.getEditor());
|
||||
myDelegate.getFocusBack();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performReplaceAll() {
|
||||
myDelegate.performReplaceAll(mySearchResults.getEditor());
|
||||
}
|
||||
|
||||
public boolean isExcluded(LiveOccurrence occurrence) {
|
||||
return mySearchResults.isExcluded(occurrence);
|
||||
}
|
||||
|
||||
public void exclude(LiveOccurrence occurrence) {
|
||||
mySearchResults.exclude(occurrence);
|
||||
myDelegate.getFocusBack();
|
||||
}
|
||||
|
||||
public boolean hasMatches() {
|
||||
return mySearchResults.hasMatches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void searchResultsUpdated(SearchResults sr) {
|
||||
removeFromEditor(mySearchResults.getEditor());
|
||||
highlightUsages();
|
||||
updateCursorHighlighting(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cursorMoved() {
|
||||
updateCursorHighlighting(true);
|
||||
}
|
||||
|
||||
public void editorChanged(SearchResults sr, Editor oldEditor) {
|
||||
removeFromEditor(mySearchResults.getEditor());
|
||||
oldEditor.getDocument().removeDocumentListener(this);
|
||||
mySearchResults.getEditor().getDocument().addDocumentListener(this);
|
||||
}
|
||||
|
||||
private void updateCursorHighlighting(boolean scroll) {
|
||||
hideBalloon();
|
||||
|
||||
if (myCursorHighlighter != null) {
|
||||
HighlightManager.getInstance(mySearchResults.getProject()).removeSegmentHighlighter(mySearchResults.getEditor(), myCursorHighlighter);
|
||||
myCursorHighlighter = null;
|
||||
}
|
||||
|
||||
LiveOccurrence cursor = mySearchResults.getCursor();
|
||||
Editor editor = mySearchResults.getEditor();
|
||||
if (cursor != null) {
|
||||
ArrayList<RangeHighlighter> dummy = new ArrayList<RangeHighlighter>();
|
||||
highlightRange(cursor.getPrimaryRange(), new TextAttributes(null, null, null, null, 0), dummy);
|
||||
if (!dummy.isEmpty()) {
|
||||
myCursorHighlighter = dummy.get(0);
|
||||
myCursorHighlighter.setCustomRenderer(new CursorRenderer());
|
||||
}
|
||||
|
||||
if (!SearchResults.insideVisibleArea(editor, cursor.getPrimaryRange()) && scroll) {
|
||||
editor.getScrollingModel().scrollTo(editor.offsetToLogicalPosition(cursor.getPrimaryRange().getStartOffset()),
|
||||
ScrollType.CENTER);
|
||||
editor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showReplacementPreview();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showReplacementPreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LivePreview(SearchResults searchResults) {
|
||||
mySearchResults = searchResults;
|
||||
searchResultsUpdated(searchResults);
|
||||
searchResults.addListener(this);
|
||||
}
|
||||
|
||||
public Delegate getDelegate() {
|
||||
return myDelegate;
|
||||
}
|
||||
|
||||
public void setDelegate(Delegate delegate) {
|
||||
myDelegate = delegate;
|
||||
}
|
||||
|
||||
|
||||
public void cleanUp() {
|
||||
removeFromEditor(mySearchResults.getEditor());
|
||||
}
|
||||
|
||||
private void removeFromEditor(Editor editor) {
|
||||
if (myReplacementBalloon != null) {
|
||||
myReplacementBalloon.hide();
|
||||
}
|
||||
|
||||
if (editor != null) {
|
||||
|
||||
for (VisibleAreaListener visibleAreaListener : myVisibleAreaListenersToRemove) {
|
||||
editor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
|
||||
}
|
||||
myVisibleAreaListenersToRemove.clear();
|
||||
for (RangeHighlighter h : myHighlighters) {
|
||||
HighlightManager.getInstance(mySearchResults.getProject()).removeSegmentHighlighter(editor, h);
|
||||
}
|
||||
if (myCursorHighlighter != null) {
|
||||
HighlightManager.getInstance(mySearchResults.getProject()).removeSegmentHighlighter(editor, myCursorHighlighter);
|
||||
myCursorHighlighter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void highlightUsages() {
|
||||
if (mySearchResults.getEditor() == null) return;
|
||||
for (LiveOccurrence o : mySearchResults.getOccurrences()) {
|
||||
for (TextRange textRange : o.getSecondaryRanges()) {
|
||||
highlightRange(textRange, OTHER_TARGETS_ATTRIBUTES, myHighlighters);
|
||||
}
|
||||
if (mySearchResults.isExcluded(o)) {
|
||||
highlightRange(o.getPrimaryRange(), EXCLUDED_TARGET_ATTRIBUTES, myHighlighters);
|
||||
} else {
|
||||
highlightRange(o.getPrimaryRange(), MAIN_TARGET_ATTRIBUTES, myHighlighters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showReplacementPreview() {
|
||||
hideBalloon();
|
||||
final LiveOccurrence cursor = mySearchResults.getCursor();
|
||||
final Editor editor = mySearchResults.getEditor();
|
||||
if (myDelegate != null && cursor != null) {
|
||||
String replacementPreviewText = myDelegate.getReplacementPreviewText(editor, cursor);
|
||||
if (replacementPreviewText != null) {
|
||||
|
||||
ReplacementView replacementView = new ReplacementView(replacementPreviewText, cursor);
|
||||
replacementView.setDelegate(this);
|
||||
|
||||
BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(replacementView);
|
||||
balloonBuilder.setFadeoutTime(0);
|
||||
balloonBuilder.setFillColor(IdeTooltipManager.GRAPHITE_COLOR);
|
||||
balloonBuilder.setAnimationCycle(0);
|
||||
balloonBuilder.setHideOnClickOutside(false);
|
||||
balloonBuilder.setHideOnKeyOutside(false);
|
||||
balloonBuilder.setHideOnAction(false);
|
||||
balloonBuilder.setCloseButtonEnabled(true);
|
||||
myReplacementBalloon = balloonBuilder.createBalloon();
|
||||
final int startOffset = cursor.getPrimaryRange().getStartOffset();
|
||||
final int endOffset = cursor.getPrimaryRange().getEndOffset();
|
||||
|
||||
myReplacementBalloon.show(new ReplacementBalloonPositionTracker(editor, startOffset, endOffset, cursor), Balloon.Position.above);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideBalloon() {
|
||||
if (myReplacementBalloon != null) {
|
||||
myReplacementBalloon.hide();
|
||||
myReplacementBalloon = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void highlightRange(TextRange textRange, TextAttributes attributes, Collection<RangeHighlighter> highlighters) {
|
||||
HighlightManager highlightManager = HighlightManager.getInstance(mySearchResults.getProject());
|
||||
if (highlightManager != null) {
|
||||
highlightManager.addRangeHighlight(mySearchResults.getEditor(),
|
||||
textRange.getStartOffset(), textRange.getEndOffset(),
|
||||
attributes, false, highlighters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static class CursorRenderer implements CustomHighlighterRenderer {
|
||||
@Override
|
||||
public void paint(Editor editor, RangeHighlighter highlighter, Graphics g) {
|
||||
Document document = editor.getDocument();
|
||||
int offset = highlighter.getStartOffset();
|
||||
while (offset < highlighter.getEndOffset()) {
|
||||
int line = document.getLineNumber(offset);
|
||||
int newOffset = document.getLineEndOffset(line);
|
||||
newOffset = Math.min(highlighter.getEndOffset(), newOffset);
|
||||
drawSegment(editor, new TextRange(offset, newOffset), g);
|
||||
offset = newOffset+1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void drawSegment(Editor editor, Segment highlighter, Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
VisualPosition startVp = editor.offsetToVisualPosition(highlighter.getStartOffset());
|
||||
VisualPosition endVp = editor.offsetToVisualPosition(highlighter.getEndOffset());
|
||||
Point start = editor.visualPositionToXY(startVp);
|
||||
Point end = editor.visualPositionToXY(endVp);
|
||||
g2d.setColor(new Color(50, 50, 50));
|
||||
g2d.translate(0, start.y - 4);
|
||||
Color c1 = new Color(220, 200, 130);
|
||||
Color c2 = new Color(220, 170, 30);
|
||||
int endX = start.x != end.x ? end.x : end.x + 2;
|
||||
UIUtil.drawSearchMatch(g2d, start.x - 1, endX + 1, editor.getLineHeight() + 2 * 4, c1, c2);
|
||||
g2d.translate(0, -start.y + 4);
|
||||
}
|
||||
}
|
||||
|
||||
private class ReplacementBalloonPositionTracker extends PositionTracker<Balloon> {
|
||||
private final Editor myEditor;
|
||||
private final int myStartOffset;
|
||||
private final int myEndOffset;
|
||||
private final LiveOccurrence myCursor;
|
||||
|
||||
public ReplacementBalloonPositionTracker(Editor editor, int startOffset, int endOffset, LiveOccurrence cursor) {
|
||||
super(editor.getContentComponent());
|
||||
myEditor = editor;
|
||||
myStartOffset = startOffset;
|
||||
myEndOffset = endOffset;
|
||||
myCursor = cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelativePoint recalculateLocation(final Balloon object) {
|
||||
Point startPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(myStartOffset));
|
||||
Point endPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(myEndOffset));
|
||||
Point point = new Point((startPoint.x + endPoint.x)/2, startPoint.y);
|
||||
if (!SearchResults.insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
object.hide();
|
||||
}
|
||||
});
|
||||
|
||||
VisibleAreaListener visibleAreaListener = new VisibleAreaListener() {
|
||||
@Override
|
||||
public void visibleAreaChanged(VisibleAreaEvent e) {
|
||||
if (SearchResults.insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
|
||||
showReplacementPreview();
|
||||
final VisibleAreaListener visibleAreaListener = this;
|
||||
myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
|
||||
myVisibleAreaListenersToRemove.remove(visibleAreaListener);
|
||||
}
|
||||
}
|
||||
};
|
||||
myEditor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
|
||||
myVisibleAreaListenersToRemove.add(visibleAreaListener);
|
||||
|
||||
}
|
||||
return new RelativePoint(myEditor.getContentComponent(), point);
|
||||
}
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package com.intellij.find.impl.livePreview;
|
||||
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindUtil;
|
||||
import com.intellij.find.impl.FindResultImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.util.Alarm;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil.ReplaceDelegate {
|
||||
|
||||
private static final String EMPTY_STRING_DISPLAY_TEXT = "<Empty string>";
|
||||
|
||||
private static final int USER_ACTIVITY_TRIGGERING_DELAY = 300;
|
||||
|
||||
private int myUserActivityDelay = USER_ACTIVITY_TRIGGERING_DELAY;
|
||||
|
||||
private final Alarm myLivePreviewAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
|
||||
|
||||
private SearchResults mySearchResults;
|
||||
private LivePreview myLivePreview;
|
||||
|
||||
public LivePreviewControllerBase(SearchResults searchResults, LivePreview livePreview) {
|
||||
mySearchResults = searchResults;
|
||||
myLivePreview = livePreview;
|
||||
myLivePreview.setDelegate(this);
|
||||
}
|
||||
|
||||
public int getUserActivityDelay() {
|
||||
return myUserActivityDelay;
|
||||
}
|
||||
|
||||
public void setUserActivityDelay(int userActivityDelay) {
|
||||
myUserActivityDelay = userActivityDelay;
|
||||
}
|
||||
|
||||
public void updateInBackground(final FindModel findModel) {
|
||||
myLivePreviewAlarm.cancelAllRequests();
|
||||
if (findModel == null) return;
|
||||
Runnable request = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mySearchResults.updateThreadSafe(findModel);
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
request.run();
|
||||
} else {
|
||||
myLivePreviewAlarm.addRequest(request, myUserActivityDelay);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence) {
|
||||
String foundString = editor.getDocument().getText(liveOccurrence.getPrimaryRange());
|
||||
String documentText = editor.getDocument().getText();
|
||||
FindModel currentModel = mySearchResults.getFindModel();
|
||||
String stringToReplace = null;
|
||||
|
||||
if (currentModel != null) {
|
||||
if (currentModel.isReplaceState()) {
|
||||
FindManager findManager = FindManager.getInstance(editor.getProject());
|
||||
try {
|
||||
stringToReplace = findManager.getStringToReplace(foundString, currentModel,
|
||||
liveOccurrence.getPrimaryRange().getStartOffset(), documentText);
|
||||
}
|
||||
catch (FindManager.MalformedReplacementStringException e) {
|
||||
return null;
|
||||
}
|
||||
if (stringToReplace != null && stringToReplace.isEmpty()) {
|
||||
stringToReplace = EMPTY_STRING_DISPLAY_TEXT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return stringToReplace;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TextRange performReplace(final LiveOccurrence occurrence, final String replacement, final Editor editor) {
|
||||
TextRange range = occurrence.getPrimaryRange();
|
||||
FindModel findModel = mySearchResults.getFindModel();
|
||||
try {
|
||||
return FindUtil.doReplace(editor.getProject(), editor.getDocument(), findModel, new FindResultImpl(range.getStartOffset(), range.getEndOffset()),
|
||||
FindManager.getInstance(editor.getProject()).getStringToReplace(editor.getDocument().getText(range), findModel),
|
||||
true, new ArrayList<Pair<TextRange, String>>());
|
||||
}
|
||||
catch (FindManager.MalformedReplacementStringException e) {
|
||||
/**/
|
||||
}
|
||||
mySearchResults.updateThreadSafe(findModel);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performReplaceAll(Editor e) {
|
||||
FindUtil.replace(e.getProject(), e, 0, mySearchResults.getFindModel(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getFocusBack() {}
|
||||
|
||||
@Override
|
||||
public boolean shouldReplace(TextRange range, String replace) {
|
||||
for (LiveOccurrence o : mySearchResults.getExcluded()) {
|
||||
TextRange primaryRange = o.getPrimaryRange();
|
||||
if (primaryRange.equals(range)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.intellij.find.impl.livePreview;
|
||||
|
||||
import com.intellij.ide.IdeTooltipManager;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class ReplacementView extends JPanel {
|
||||
|
||||
private String myReplacement;
|
||||
private LiveOccurrence myOccurrence;
|
||||
private JButton myStatusButton;
|
||||
|
||||
public interface Delegate {
|
||||
void performReplacement(LiveOccurrence occurrence, String replacement);
|
||||
void performReplaceAll();
|
||||
boolean isExcluded(LiveOccurrence occurrence);
|
||||
void exclude(LiveOccurrence occurrence);
|
||||
}
|
||||
|
||||
private Delegate myDelegate;
|
||||
|
||||
public Delegate getDelegate() {
|
||||
return myDelegate;
|
||||
}
|
||||
|
||||
public void setDelegate(Delegate delegate) {
|
||||
this.myDelegate = delegate;
|
||||
updateStatusLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics graphics) {
|
||||
|
||||
}
|
||||
|
||||
public ReplacementView(final String replacement, final LiveOccurrence occurrence) {
|
||||
myReplacement = replacement;
|
||||
myOccurrence = occurrence;
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
|
||||
JLabel jLabel = new JLabel(replacement);
|
||||
jLabel.setForeground(Color.WHITE);
|
||||
JPanel labelPane = new JPanel(new FlowLayout()) {
|
||||
@Override
|
||||
protected void paintComponent(Graphics graphics) {}
|
||||
};
|
||||
labelPane.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
labelPane.add(jLabel);
|
||||
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.gridx = c.gridy = 0;
|
||||
c.gridwidth = 2;
|
||||
c.gridheight = 1;
|
||||
add(labelPane, c);
|
||||
JButton replace = new JButton("Replace");
|
||||
|
||||
replace.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
if (myDelegate != null) {
|
||||
myDelegate.performReplacement(occurrence, replacement);
|
||||
}
|
||||
}
|
||||
});
|
||||
replace.setPreferredSize(new Dimension(80, 20));
|
||||
replace.setMnemonic('R');
|
||||
JPanel buttonsPane = new JPanel(){
|
||||
@Override
|
||||
protected void paintComponent(Graphics graphics) { }
|
||||
};
|
||||
JButton replaceAllButton = new JButton("Replace all");
|
||||
|
||||
replaceAllButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
if (myDelegate != null) {
|
||||
myDelegate.performReplaceAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
replaceAllButton.setPreferredSize(new Dimension(100, 20));
|
||||
replaceAllButton.setMnemonic('a');
|
||||
|
||||
myStatusButton = new JButton("Exclude");
|
||||
myStatusButton.setPreferredSize(new Dimension(80, 20));
|
||||
myStatusButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
myDelegate.exclude(myOccurrence);
|
||||
updateStatusLabel();
|
||||
}
|
||||
});
|
||||
myStatusButton.setMnemonic('l');
|
||||
buttonsPane.add(myStatusButton);
|
||||
|
||||
setBackground(IdeTooltipManager.GRAPHITE_COLOR);
|
||||
if (SystemInfo.isMac) {
|
||||
Font f = getFont();
|
||||
setFont(f.deriveFont(f.getStyle(), f.getSize() - 4));
|
||||
}
|
||||
|
||||
buttonsPane.add(replace);
|
||||
buttonsPane.add(replaceAllButton);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 1;
|
||||
|
||||
c.gridwidth = 3;
|
||||
c.gridheight = 1;
|
||||
add(buttonsPane, c);
|
||||
setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
}
|
||||
|
||||
private void updateStatusLabel() {
|
||||
myStatusButton.setText(myDelegate.isExcluded(myOccurrence) ? "Include" : "Exclude");
|
||||
myStatusButton.repaint();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
package com.intellij.find.impl.livePreview;
|
||||
|
||||
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindResult;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public class SearchResults {
|
||||
|
||||
private int myActualFound = 0;
|
||||
|
||||
private List<SearchResultsListener> myListeners = new ArrayList<SearchResultsListener>();
|
||||
|
||||
private LiveOccurrence myCursor;
|
||||
|
||||
private List<LiveOccurrence> myOccurrences = new ArrayList<LiveOccurrence>();
|
||||
private Set<LiveOccurrence> myExcluded = new HashSet<LiveOccurrence>();
|
||||
|
||||
private Editor myEditor;
|
||||
|
||||
private FindModel myFindModel;
|
||||
|
||||
private int myMatchesLimit = 100;
|
||||
|
||||
public SearchResults(Editor editor) {
|
||||
myEditor = editor;
|
||||
}
|
||||
|
||||
public int getActualFound() {
|
||||
return myActualFound;
|
||||
}
|
||||
|
||||
public boolean hasMatches() {
|
||||
return !getOccurrences().isEmpty();
|
||||
}
|
||||
|
||||
public FindModel getFindModel() {
|
||||
return myFindModel;
|
||||
}
|
||||
|
||||
public boolean isExcluded(LiveOccurrence occurrence) {
|
||||
return myExcluded.contains(occurrence);
|
||||
}
|
||||
|
||||
public void exclude(LiveOccurrence occurrence) {
|
||||
if (myExcluded.contains(occurrence)) {
|
||||
myExcluded.remove(occurrence);
|
||||
} else {
|
||||
myExcluded.add(occurrence);
|
||||
}
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
public Set<LiveOccurrence> getExcluded() {
|
||||
return myExcluded;
|
||||
}
|
||||
|
||||
public interface SearchResultsListener {
|
||||
void searchResultsUpdated(SearchResults sr);
|
||||
void editorChanged(SearchResults sr, Editor oldEditor);
|
||||
|
||||
void cursorMoved();
|
||||
}
|
||||
|
||||
public void addListener(SearchResultsListener srl) {
|
||||
myListeners.add(srl);
|
||||
}
|
||||
|
||||
public void removeListener(SearchResultsListener srl) {
|
||||
myListeners.remove(srl);
|
||||
}
|
||||
|
||||
public int getMatchesLimit() {
|
||||
return myMatchesLimit;
|
||||
}
|
||||
|
||||
public void setMatchesLimit(int matchesLimit) {
|
||||
myMatchesLimit = matchesLimit;
|
||||
}
|
||||
|
||||
public LiveOccurrence getCursor() {
|
||||
return myCursor;
|
||||
}
|
||||
|
||||
public List<LiveOccurrence> getOccurrences() {
|
||||
return myOccurrences;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myEditor.getProject();
|
||||
}
|
||||
|
||||
public synchronized void setEditor(Editor editor) {
|
||||
Editor oldOne = myEditor;
|
||||
myEditor = editor;
|
||||
notifyEditorChanged(oldOne);
|
||||
}
|
||||
|
||||
private void notifyEditorChanged(Editor oldOne) {
|
||||
for (SearchResultsListener listener : myListeners) {
|
||||
listener.editorChanged(this, oldOne);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Editor getEditor() {
|
||||
return myEditor;
|
||||
}
|
||||
|
||||
private static void findResultsToOccurrences(ArrayList<FindResult> results, Collection<LiveOccurrence> occurrences) {
|
||||
for (FindResult r : results) {
|
||||
LiveOccurrence occurrence = new LiveOccurrence();
|
||||
occurrence.setPrimaryRange(r);
|
||||
occurrences.add(occurrence);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateThreadSafe(final FindModel findModel) {
|
||||
final ArrayList<LiveOccurrence> occurrences = new ArrayList<LiveOccurrence>();
|
||||
final Editor editor = getEditor();
|
||||
|
||||
final ArrayList<FindResult> results = new ArrayList<FindResult>();
|
||||
if (findModel != null) {
|
||||
|
||||
TextRange r = findModel.isGlobal() ? new TextRange(0, Integer.MAX_VALUE) :
|
||||
new TextRange(editor.getSelectionModel().getSelectionStart(),
|
||||
editor.getSelectionModel().getSelectionEnd());
|
||||
if (r.getLength() == 0) {
|
||||
r = new TextRange(0, Integer.MAX_VALUE);
|
||||
}
|
||||
int offset = r.getStartOffset();
|
||||
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
|
||||
|
||||
while (true) {
|
||||
FindManager findManager = FindManager.getInstance(editor.getProject());
|
||||
FindResult result = findManager.findString(editor.getDocument().getCharsSequence(), offset, findModel, virtualFile);
|
||||
if (!result.isStringFound()) break;
|
||||
int newOffset = result.getEndOffset();
|
||||
if (offset == newOffset || result.getEndOffset() > r.getEndOffset()) break;
|
||||
offset = newOffset;
|
||||
results.add(result);
|
||||
|
||||
if (results.size() > myMatchesLimit) break;
|
||||
}
|
||||
if (results.size() < myMatchesLimit) {
|
||||
|
||||
findResultsToOccurrences(results, occurrences);
|
||||
}
|
||||
}
|
||||
|
||||
final Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
searchCompleted(occurrences, results.size(), editor, findModel);
|
||||
}
|
||||
};
|
||||
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
ApplicationManager.getApplication().invokeLater(r);
|
||||
} else {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void searchCompleted(List<LiveOccurrence> occurrences, int size, Editor editor, FindModel findModel) {
|
||||
if (editor == getEditor()) {
|
||||
myOccurrences = occurrences;
|
||||
final TextRange oldCursorRange = myCursor != null ? myCursor.getPrimaryRange() : null;
|
||||
Collections.sort(myOccurrences, new Comparator<LiveOccurrence>() {
|
||||
@Override
|
||||
public int compare(LiveOccurrence liveOccurrence, LiveOccurrence liveOccurrence1) {
|
||||
return liveOccurrence.getPrimaryRange().getStartOffset() - liveOccurrence1.getPrimaryRange().getStartOffset();
|
||||
}
|
||||
});
|
||||
|
||||
updateCursor(oldCursorRange);
|
||||
myFindModel = findModel;
|
||||
myActualFound = size;
|
||||
notifyChanged();
|
||||
if (oldCursorRange == null) {
|
||||
notifyCursorMoved();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCursor(TextRange oldCursorRange) {
|
||||
if (!tryToRepairOldCursor(oldCursorRange)) {
|
||||
LiveOccurrence afterCaret = firstOccurrenceAfterCaret();
|
||||
if (afterCaret != null) {
|
||||
myCursor = afterCaret;
|
||||
} else {
|
||||
LiveOccurrence occurrence = firstVisibleOccurrence();
|
||||
myCursor = occurrence;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyChanged() {
|
||||
for (SearchResultsListener listener : myListeners) {
|
||||
listener.searchResultsUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean insideVisibleArea(Editor e, TextRange r) {
|
||||
Rectangle visibleArea = e.getScrollingModel().getVisibleArea();
|
||||
Point point = e.logicalPositionToXY(e.offsetToLogicalPosition(r.getStartOffset()));
|
||||
|
||||
return visibleArea.contains(point);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence firstVisibleOccurrence() {
|
||||
int offset = Integer.MAX_VALUE;
|
||||
LiveOccurrence firstOccurrence = null;
|
||||
LiveOccurrence firstVisibleOccurrence = null;
|
||||
for (LiveOccurrence o : getOccurrences()) {
|
||||
if (insideVisibleArea(myEditor, o.getPrimaryRange())) {
|
||||
if (firstVisibleOccurrence == null || o.getPrimaryRange().getStartOffset() < firstVisibleOccurrence.getPrimaryRange().getStartOffset()) {
|
||||
firstVisibleOccurrence = o;
|
||||
}
|
||||
}
|
||||
if (o.getPrimaryRange().getStartOffset() < offset) {
|
||||
offset = o.getPrimaryRange().getStartOffset();
|
||||
firstOccurrence = o;
|
||||
}
|
||||
}
|
||||
return firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence firstOccurrenceAfterCaret() {
|
||||
LiveOccurrence afterCaret = null;
|
||||
int caret = myEditor.getCaretModel().getOffset();
|
||||
for (LiveOccurrence occurrence : getOccurrences()) {
|
||||
if (occurrence.getPrimaryRange().getStartOffset() >= caret) {
|
||||
if (afterCaret == null || occurrence.getPrimaryRange().getStartOffset() < afterCaret.getPrimaryRange().getStartOffset() ) {
|
||||
afterCaret = occurrence;
|
||||
}
|
||||
}
|
||||
}
|
||||
return afterCaret;
|
||||
}
|
||||
|
||||
private boolean tryToRepairOldCursor(TextRange oldCursorRange) {
|
||||
if (oldCursorRange == null) return false;
|
||||
LiveOccurrence mayBeOldCursor = null;
|
||||
for (LiveOccurrence searchResult : getOccurrences()) {
|
||||
if (searchResult.getPrimaryRange().intersects(oldCursorRange)) {
|
||||
mayBeOldCursor = searchResult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mayBeOldCursor != null) {
|
||||
myCursor = mayBeOldCursor;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence prevOccurrence(LiveOccurrence o) {
|
||||
for (int i = 0; i < getOccurrences().size(); ++i) {
|
||||
if (o == getOccurrences().get(i)) {
|
||||
if (i > 0) {
|
||||
return getOccurrences().get(i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LiveOccurrence nextOccurrence(LiveOccurrence o) {
|
||||
boolean found = false;
|
||||
for (LiveOccurrence occurrence : getOccurrences()) {
|
||||
if (found) {
|
||||
return occurrence;
|
||||
}
|
||||
if (o == occurrence) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void prevOccurrence() {
|
||||
LiveOccurrence prev = prevOccurrence(myCursor);
|
||||
if (prev == null && !getOccurrences().isEmpty()) {
|
||||
prev = getOccurrences().get(getOccurrences().size() - 1);
|
||||
}
|
||||
moveCursorTo(prev);
|
||||
}
|
||||
|
||||
public void nextOccurrence() {
|
||||
LiveOccurrence next = nextOccurrence(myCursor);
|
||||
if (next == null && !getOccurrences().isEmpty()) {
|
||||
next = getOccurrences().get(0);
|
||||
}
|
||||
moveCursorTo(next);
|
||||
}
|
||||
|
||||
public void moveCursorTo(LiveOccurrence next) {
|
||||
if (next != null) {
|
||||
setCursor(next);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCursor(LiveOccurrence liveOccurrence) {
|
||||
myCursor = liveOccurrence;
|
||||
notifyCursorMoved();
|
||||
}
|
||||
|
||||
private void notifyCursorMoved() {
|
||||
for (SearchResultsListener listener : myListeners) {
|
||||
listener.cursorMoved();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.intellij.formatting;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.components.ApplicationComponent;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
@@ -25,6 +26,7 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.formatter.FormatterUtil;
|
||||
import com.intellij.psi.formatter.FormattingDocumentModelImpl;
|
||||
import com.intellij.psi.formatter.PsiBasedFormattingModel;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -92,6 +94,9 @@ public class FormatterImpl extends FormatterEx
|
||||
|
||||
@Override
|
||||
public void setProgressIndicator(@NotNull FormattingProgressIndicatorImpl progressIndicator) {
|
||||
if (!FormatterUtil.FORMATTER_ACTION_NAMES.contains(CommandProcessor.getInstance().getCurrentCommandName())) {
|
||||
return;
|
||||
}
|
||||
myProgressIndicator = progressIndicator;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.formatting;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.command.undo.UndoManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
@@ -27,6 +28,7 @@ import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.formatter.FormatterUtil;
|
||||
import com.intellij.util.SequentialTask;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
@@ -90,9 +90,10 @@ public class PlatformPackageUtil {
|
||||
GlobalSearchScope scope,
|
||||
String packageName,
|
||||
PsiDirectory baseDir,
|
||||
boolean askUserToCreate) throws IncorrectOperationException {
|
||||
boolean askUserToCreate,
|
||||
ThreeState chooseFlag) throws IncorrectOperationException {
|
||||
PsiDirectory psiDirectory = null;
|
||||
if (!"".equals(packageName)) {
|
||||
if (chooseFlag == ThreeState.UNSURE && !"".equals(packageName)) {
|
||||
String rootPackage = findLongestExistingPackage(project, packageName, scope);
|
||||
if (rootPackage != null) {
|
||||
int beginIndex = rootPackage.length() + 1;
|
||||
@@ -108,19 +109,25 @@ public class PlatformPackageUtil {
|
||||
}
|
||||
|
||||
if (psiDirectory == null) {
|
||||
if (module != null && !checkSourceRootsConfigured(module)) return null;
|
||||
final GlobalSearchScope scope_ = scope;
|
||||
List<PsiDirectory> dirs =
|
||||
ContainerUtil
|
||||
.mapNotNull(ProjectRootManager.getInstance(project).getContentSourceRoots(), new Function<VirtualFile, PsiDirectory>() {
|
||||
@Override
|
||||
public PsiDirectory fun(VirtualFile virtualFile) {
|
||||
return scope_.contains(virtualFile) ? PsiManager.getInstance(project).findDirectory(virtualFile) : null;
|
||||
}
|
||||
});
|
||||
psiDirectory = DirectoryChooserUtil.selectDirectory(project, dirs.toArray(new PsiDirectory[dirs.size()]), baseDir,
|
||||
File.separatorChar + packageName.replace('.', File.separatorChar));
|
||||
if (psiDirectory == null) return null;
|
||||
if (chooseFlag == ThreeState.NO && baseDir != null) {
|
||||
VirtualFile sourceRoot = ProjectRootManager.getInstance(project).getFileIndex().getSourceRootForFile(baseDir.getVirtualFile());
|
||||
psiDirectory = PsiManager.getInstance(project).findDirectory(sourceRoot);
|
||||
}
|
||||
else {
|
||||
if (module != null && !checkSourceRootsConfigured(module)) return null;
|
||||
final GlobalSearchScope scope_ = scope;
|
||||
List<PsiDirectory> dirs =
|
||||
ContainerUtil
|
||||
.mapNotNull(ProjectRootManager.getInstance(project).getContentSourceRoots(), new Function<VirtualFile, PsiDirectory>() {
|
||||
@Override
|
||||
public PsiDirectory fun(VirtualFile virtualFile) {
|
||||
return scope_.contains(virtualFile) ? PsiManager.getInstance(project).findDirectory(virtualFile) : null;
|
||||
}
|
||||
});
|
||||
psiDirectory = DirectoryChooserUtil.selectDirectory(project, dirs.toArray(new PsiDirectory[dirs.size()]), baseDir,
|
||||
File.separatorChar + packageName.replace('.', File.separatorChar));
|
||||
if (psiDirectory == null) return null;
|
||||
}
|
||||
}
|
||||
|
||||
String restOfName = packageName;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.psi.formatter;
|
||||
|
||||
import com.intellij.codeInsight.actions.ReformatAndOptimizeImportsProcessor;
|
||||
import com.intellij.codeInsight.actions.ReformatCodeProcessor;
|
||||
import com.intellij.lang.ASTFactory;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
@@ -27,12 +29,21 @@ import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.CharTable;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class FormatterUtil {
|
||||
|
||||
private static final List<FormatterUtilHelper> ourHelpers = ContainerUtil.createEmptyCOWList();
|
||||
|
||||
public static final Collection<String> FORMATTER_ACTION_NAMES = Collections.unmodifiableCollection(ContainerUtil.addAll(
|
||||
new HashSet<String>(), ReformatAndOptimizeImportsProcessor.COMMAND_NAME, ReformatCodeProcessor.COMMAND_NAME
|
||||
));
|
||||
|
||||
private FormatterUtil() {
|
||||
}
|
||||
|
||||
+2
@@ -41,6 +41,8 @@ interface SmartPointerElementInfo {
|
||||
boolean pointsToTheSameElementAs(SmartPointerElementInfo other);
|
||||
|
||||
VirtualFile getVirtualFile();
|
||||
|
||||
@Nullable
|
||||
Segment getRange();
|
||||
@NotNull Project getProject();
|
||||
}
|
||||
|
||||
+2
-2
@@ -47,8 +47,8 @@ public class MoveFilesOrDirectoriesProcessor extends BaseRefactoringProcessor {
|
||||
|
||||
protected final PsiElement[] myElementsToMove;
|
||||
private final boolean mySearchForReferences;
|
||||
private final boolean mySearchInComments;
|
||||
private final boolean mySearchInNonJavaFiles;
|
||||
protected final boolean mySearchInComments;
|
||||
protected final boolean mySearchInNonJavaFiles;
|
||||
private final PsiDirectory myNewParent;
|
||||
private final MoveCallback myMoveCallback;
|
||||
private NonCodeUsageInfo[] myNonCodeUsages;
|
||||
|
||||
@@ -25,14 +25,17 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.LanguageParserDefinitions;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.*;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
|
||||
public class TextOccurrencesUtil {
|
||||
private TextOccurrencesUtil() {
|
||||
@@ -41,7 +44,7 @@ public class TextOccurrencesUtil {
|
||||
public static void addTextOccurences(@NotNull PsiElement element,
|
||||
@NotNull String stringToSearch,
|
||||
@NotNull GlobalSearchScope searchScope,
|
||||
@NotNull final List<UsageInfo> results,
|
||||
@NotNull final Collection<UsageInfo> results,
|
||||
@NotNull final UsageInfoFactory factory) {
|
||||
processTextOccurences(element, stringToSearch, searchScope, new Processor<UsageInfo>() {
|
||||
public boolean process(UsageInfo t) {
|
||||
@@ -104,7 +107,7 @@ public class TextOccurrencesUtil {
|
||||
|
||||
public static void addUsagesInStringsAndComments(@NotNull PsiElement element,
|
||||
@NotNull String stringToSearch,
|
||||
@NotNull final List<UsageInfo> results,
|
||||
@NotNull final Collection<UsageInfo> results,
|
||||
@NotNull final UsageInfoFactory factory) {
|
||||
processUsagesInStringsAndComments(element, stringToSearch, false, new PairProcessor<PsiElement, TextRange>() {
|
||||
public boolean process(PsiElement commentOrLiteral, TextRange textRange) {
|
||||
@@ -155,6 +158,33 @@ public class TextOccurrencesUtil {
|
||||
return FindUsagesUtil.isSearchForTextOccurrencesAvailable(element, false, handler);
|
||||
}
|
||||
|
||||
public static void findNonCodeUsages(PsiElement element, String stringToSearch, boolean searchInStringsAndComments,
|
||||
boolean searchInNonJavaFiles, String newQName, Collection<UsageInfo> results) {
|
||||
if (searchInStringsAndComments || searchInNonJavaFiles) {
|
||||
UsageInfoFactory factory = createUsageInfoFactory(element, newQName);
|
||||
|
||||
if (searchInStringsAndComments) {
|
||||
addUsagesInStringsAndComments(element, stringToSearch, results, factory);
|
||||
}
|
||||
|
||||
if (searchInNonJavaFiles) {
|
||||
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(element.getProject());
|
||||
addTextOccurences(element, stringToSearch, projectScope, results, factory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static UsageInfoFactory createUsageInfoFactory(final PsiElement element,
|
||||
final String newQName) {
|
||||
return new UsageInfoFactory() {
|
||||
public UsageInfo createUsageInfo(@NotNull PsiElement usage, int startOffset, int endOffset) {
|
||||
int start = usage.getTextRange().getStartOffset();
|
||||
return NonCodeUsageInfo.create(usage.getContainingFile(), start + startOffset, start + endOffset, element,
|
||||
newQName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public interface UsageInfoFactory {
|
||||
UsageInfo createUsageInfo(@NotNull PsiElement usage, int startOffset, int endOffset);
|
||||
}
|
||||
|
||||
+4
-5
@@ -39,15 +39,14 @@ public class FeatureStatisticsBundle {
|
||||
}
|
||||
|
||||
private static ResourceBundle getBundle(final String key) {
|
||||
// bundles provided by plugins
|
||||
for (FeatureStatisticsBundleProvider provider : FeatureStatisticsBundleProvider.EP_NAME.getExtensions()) {
|
||||
final ResourceBundle bundle = provider.getBundleFor(key);
|
||||
if (bundle != null) {
|
||||
final FeatureStatisticsBundleProvider[] providers = FeatureStatisticsBundleProvider.EP_NAME.getExtensions();
|
||||
for (FeatureStatisticsBundleProvider provider : providers) {
|
||||
final ResourceBundle bundle = provider.getBundle();
|
||||
if (bundle.containsKey(key)) {
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
|
||||
// default bundle
|
||||
ResourceBundle bundle = null;
|
||||
if (ourBundle != null) bundle = ourBundle.get();
|
||||
if (bundle == null) {
|
||||
|
||||
+2
-3
@@ -16,16 +16,15 @@
|
||||
package com.intellij.featureStatistics;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
* @author Roman.Chernyatchik
|
||||
*/
|
||||
public interface FeatureStatisticsBundleProvider {
|
||||
ExtensionPointName<FeatureStatisticsBundleProvider> EP_NAME = new ExtensionPointName<FeatureStatisticsBundleProvider>("com.intellij.featureStatBundle");
|
||||
|
||||
@Nullable
|
||||
ResourceBundle getBundleFor(String key);
|
||||
ResourceBundle getBundle();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ public interface IdeActions {
|
||||
@NonNls String ACTION_EDITOR_NEXT_TEMPLATE_VARIABLE = "NextTemplateVariable";
|
||||
@NonNls String ACTION_EDITOR_PREVIOUS_TEMPLATE_VARIABLE = "PreviousTemplateVariable";
|
||||
|
||||
@NonNls String ACTION_EDITOR_REFORMAT = "ReformatCode";
|
||||
|
||||
|
||||
@NonNls String ACTION_COMMENT_LINE = "CommentByLineComment";
|
||||
|
||||
+16
-4
@@ -22,8 +22,10 @@ import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
@@ -46,14 +48,24 @@ public class ProductivityFeaturesRegistryImpl extends ProductivityFeaturesRegist
|
||||
|
||||
public ProductivityFeaturesRegistryImpl() {
|
||||
try {
|
||||
final Document document = JDOMUtil.loadResourceDocument(new URL("file:///ProductivityFeaturesRegistry.xml"));
|
||||
final Element root = document.getRootElement();
|
||||
readGroups(root);
|
||||
readFilters(root);
|
||||
readFromXml("file:///ProductivityFeaturesRegistry.xml");
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
|
||||
try {
|
||||
readFromXml("file:///IdeSpecificFeatures.xml");
|
||||
}
|
||||
catch (Exception e) {// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void readFromXml(String path) throws JDOMException, IOException {
|
||||
final Document document = JDOMUtil.loadResourceDocument(new URL(path));
|
||||
final Element root = document.getRootElement();
|
||||
readGroups(root);
|
||||
readFilters(root);
|
||||
}
|
||||
|
||||
private void lazyLoadFromPluginsFeaturesProviders() {
|
||||
|
||||
@@ -19,9 +19,7 @@ import com.intellij.featureStatistics.FeatureDescriptor;
|
||||
import com.intellij.featureStatistics.ProductivityFeaturesProvider;
|
||||
import com.intellij.ide.GeneralSettings;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
@@ -38,10 +36,8 @@ import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class TipPanel extends JPanel {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.TipPanel");
|
||||
private static final int DEFAULT_WIDTH = 400;
|
||||
private static final int DEFAULT_HEIGHT = 200;
|
||||
private final JCheckBox myCheckBox;
|
||||
@@ -92,10 +88,10 @@ public class TipPanel extends JPanel {
|
||||
});
|
||||
add(myCheckBox, BorderLayout.SOUTH);
|
||||
try {
|
||||
readTips();
|
||||
readTips("/tips/tips.xml");
|
||||
readTips("/tips/IdeSpecificTips.xml");
|
||||
}
|
||||
catch (Exception exception) {
|
||||
|
||||
catch (Exception exception) {//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,10 +104,10 @@ public class TipPanel extends JPanel {
|
||||
browser.setText(IdeBundle.message("error.tips.not.found", ApplicationNamesInfo.getInstance().getFullProductName()));
|
||||
return;
|
||||
}
|
||||
GeneralSettings settings = GeneralSettings.getInstance();
|
||||
final GeneralSettings settings = GeneralSettings.getInstance();
|
||||
int lastTip = settings.getLastTip();
|
||||
|
||||
String path;
|
||||
final String path;
|
||||
lastTip--;
|
||||
if (lastTip <= 0) {
|
||||
path = myTipPaths.get(myTipPaths.size() - 1);
|
||||
@@ -126,7 +122,6 @@ public class TipPanel extends JPanel {
|
||||
|
||||
private void setTip (String path, int lastTip, JEditorPane browser, GeneralSettings settings) {
|
||||
TipUIUtil.openTipInBrowser(path, browser, myPathsToProviderMap.get(path));
|
||||
|
||||
settings.setLastTip(lastTip);
|
||||
}
|
||||
|
||||
@@ -148,46 +143,21 @@ public class TipPanel extends JPanel {
|
||||
}
|
||||
|
||||
setTip(path, lastTip, browser, settings);
|
||||
/*
|
||||
try {
|
||||
String appName = ApplicationUtil.getApplicationName();
|
||||
String tipsPath = ResourceUtil.getHomePath() + File.separator + "help" + File.separator + appName + File.separator + "tips" + File.separator;
|
||||
File file = new File(tipsPath + "tip" + lastTip + ".html");
|
||||
if (!file.exists()) {
|
||||
if (lastTip == 1) {
|
||||
browser.setText("Tips not found. Make sure you installed IntelliJ IDEA correctly.");
|
||||
return;
|
||||
}
|
||||
lastTip = 1;
|
||||
file = new File(tipsPath + "tip" + lastTip + ".html");
|
||||
if (!file.exists()) {
|
||||
browser.setText("Tips not found. Make sure you installed IntelliJ IDEA correctly.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
browser.setPage(file.toURL());
|
||||
settings.setLastTip(lastTip);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private void readTips() throws Exception {
|
||||
@NonNls String tipsURL = "/tips/" + "tips.xml";
|
||||
Document document = JDOMUtil.loadDocument(getClass().getResource(tipsURL).openStream());
|
||||
if (document == null) return;
|
||||
for (Iterator iterator = document.getRootElement().getChildren(ELEMENT_TIP).iterator(); iterator.hasNext();) {
|
||||
Element element = (Element)iterator.next();
|
||||
myTipPaths.add(element.getAttributeValue(ATTRIBUTE_FILE));
|
||||
private void readTips(String tipsURL) throws Exception {
|
||||
final Document document = JDOMUtil.loadDocument(getClass().getResource(tipsURL).openStream());
|
||||
|
||||
for (Object o : document.getRootElement().getChildren(ELEMENT_TIP)) {
|
||||
Element tip = (Element)o;
|
||||
myTipPaths.add(tip.getAttributeValue(ATTRIBUTE_FILE));
|
||||
}
|
||||
final ProductivityFeaturesProvider[] providers = ApplicationManager.getApplication().getComponents(ProductivityFeaturesProvider.class);
|
||||
for (ProductivityFeaturesProvider provider : providers) {
|
||||
final FeatureDescriptor[] featureDescriptors = provider.getFeatureDescriptors();
|
||||
for (int j = 0; featureDescriptors != null && j < featureDescriptors.length; j++) {
|
||||
FeatureDescriptor featureDescriptor = featureDescriptors[j];
|
||||
myPathsToProviderMap.put(featureDescriptor.getTipFileName(), featureDescriptor.getProvider());
|
||||
|
||||
for (ProductivityFeaturesProvider provider : ProductivityFeaturesProvider.EP_NAME.getExtensions()) {
|
||||
final FeatureDescriptor[] descriptors = provider.getFeatureDescriptors();
|
||||
for (int j = 0; descriptors != null && j < descriptors.length; j++) {
|
||||
FeatureDescriptor descriptor = descriptors[j];
|
||||
myPathsToProviderMap.put(descriptor.getTipFileName(), descriptor.getProvider());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,4 +114,4 @@ codeassists.highlight.return=Highlight method exit points
|
||||
codeassists.highlight.throws=Highlight method throws
|
||||
find.recent.search=Recent searches history
|
||||
find.completion=Completion in Find Bar
|
||||
switcher=Tab and Tool Window Switcher
|
||||
switcher=Switcher
|
||||
|
||||
@@ -478,11 +478,12 @@ public class ContainerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void addAll(@NotNull Collection<T> collection, @NotNull T... elements) {
|
||||
public static <T> Collection<T> addAll(@NotNull Collection<T> collection, @NotNull T... elements) {
|
||||
//noinspection ManualArrayToCollectionCopy
|
||||
for (T element : elements) {
|
||||
collection.add(element);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static <T, U extends T> U findInstance(@NotNull Iterable<T> iterable, @NotNull Class<U> aClass) {
|
||||
|
||||
@@ -108,14 +108,12 @@ public class ThreeStateCheckBox extends JCheckBox {
|
||||
return myState;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics g) {
|
||||
super.paint(g);
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
switch (getState()) {
|
||||
case DONT_CARE:
|
||||
final Rectangle r = getBounds();
|
||||
final Insets i = getInsets();
|
||||
|
||||
Icon icon = getIcon();
|
||||
if (icon == null) {
|
||||
icon = UIManager.getIcon("CheckBox.icon");
|
||||
@@ -126,13 +124,24 @@ public class ThreeStateCheckBox extends JCheckBox {
|
||||
//if (selected != null) {
|
||||
// g.setColor(selected);
|
||||
//}
|
||||
final Insets i = getInsets();
|
||||
final Rectangle r = getBounds();
|
||||
final Rectangle r1 = new Rectangle();
|
||||
r1.x = i.left;
|
||||
r1.y = i.top;
|
||||
r1.width = r.width - (i.right + r1.x);
|
||||
r1.height = r.height - (i.bottom + r1.y);
|
||||
|
||||
final int width1 = icon.getIconWidth();
|
||||
final int height1 = r.height - i.top - i.bottom;
|
||||
final int yoffset = height1 / 2 - 1;
|
||||
final int xoffset = width1 / 2 - width1 / 5;
|
||||
final Rectangle r2 = new Rectangle();
|
||||
final Rectangle r3 = new Rectangle();
|
||||
SwingUtilities.layoutCompoundLabel(
|
||||
this, getFontMetrics(getFont()), getText(), icon,
|
||||
getVerticalAlignment(), getHorizontalAlignment(),
|
||||
getVerticalTextPosition(), getHorizontalTextPosition(),
|
||||
r1, r2, r3,
|
||||
getText() == null ? 0 : getIconTextGap());
|
||||
|
||||
g.fillRect(xoffset + i.left, yoffset + i.top, width1 / 3, 2);
|
||||
g.fillRect(r2.x + r2.width / 2 - r2.width / 5, r2.y + r2.height / 2 -1, r2.width / 3, 2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package com.intellij.platform;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.project.DumbAwareRunnable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
import com.intellij.openapi.vcs.VcsDirectoryMapping;
|
||||
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
|
||||
@@ -42,7 +44,7 @@ public class PlatformVcsDetector implements ProjectComponent {
|
||||
public void projectOpened() {
|
||||
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
|
||||
public void run() {
|
||||
AppUIUtil.invokeLaterIfProjectAlive(myProject, new DumbAwareRunnable() {
|
||||
final DumbAwareRunnable runnable = new DumbAwareRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VirtualFile file = ProjectBaseDirectory.getInstance(myProject).getBaseDir(myProject.getBaseDir());
|
||||
@@ -56,6 +58,12 @@ public class PlatformVcsDetector implements ProjectComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
ApplicationManager.getApplication().invokeLater(runnable, new Condition() {
|
||||
@Override
|
||||
public boolean value(Object o) {
|
||||
return (! myProject.isOpen()) || myProject.isDisposed();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1847,3 +1847,7 @@ choose.super.class.to.ignore=Choose class
|
||||
ignore.anonymous.inner.classes=Ignore anonymous inner classes
|
||||
try.with.identical.catches.display.name=Identical 'catch' branches in 'try' statement
|
||||
try.with.identical.catches.problem.descriptor=Identical 'catch' branches in 'try' statement #loc
|
||||
if.can.be.switch.display.name='if' replaceable with 'switch'
|
||||
if.can.be.switch.problem.descriptor=<code>#ref</code> statement replaceable with 'switch' statement
|
||||
if.can.be.switch.quickfix=Replace with 'switch'
|
||||
if.can.be.switch.minimum.branch.option=Minimum number of branches
|
||||
|
||||
@@ -481,6 +481,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent,
|
||||
m_inspectionClasses.add(FallthruInSwitchStatementInspection.class);
|
||||
m_inspectionClasses.add(ForLoopReplaceableByWhileInspection.class);
|
||||
m_inspectionClasses.add(ForLoopWithMissingComponentInspection.class);
|
||||
m_inspectionClasses.add(IfCanBeSwitchInspection.class);
|
||||
m_inspectionClasses.add(IfMayBeConditionalInspection.class);
|
||||
m_inspectionClasses.add(IfStatementWithIdenticalBranchesInspection.class);
|
||||
m_inspectionClasses.add(IfStatementWithTooManyBranchesInspection.class);
|
||||
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright 2011 Bas Leijdekkers
|
||||
*
|
||||
* 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.siyeh.ig.controlflow;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ui.SingleIntegerFieldOptionsPanel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.EquivalenceChecker;
|
||||
import com.siyeh.ig.psiutils.SwitchUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IfCanBeSwitchInspection extends BaseInspection {
|
||||
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public int minimumBranches = 3;
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("if.can.be.switch.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"if.can.be.switch.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new IfCanBeSwitchFix((PsiExpression) infos[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleIntegerFieldOptionsPanel(
|
||||
InspectionGadgetsBundle.message(
|
||||
"if.can.be.switch.minimum.branch.option"),
|
||||
this, "minimumBranches");
|
||||
}
|
||||
|
||||
private static class IfCanBeSwitchFix extends InspectionGadgetsFix {
|
||||
|
||||
private final PsiExpression switchExpression;
|
||||
|
||||
public IfCanBeSwitchFix(PsiExpression switchExpression) {
|
||||
this.switchExpression = switchExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("if.can.be.switch.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor)
|
||||
throws IncorrectOperationException {
|
||||
final PsiElement element = descriptor.getPsiElement().getParent();
|
||||
if (!(element instanceof PsiIfStatement)) {
|
||||
return;
|
||||
}
|
||||
PsiIfStatement ifStatement = (PsiIfStatement)element;
|
||||
boolean breaksNeedRelabeled = false;
|
||||
PsiStatement breakTarget = null;
|
||||
String labelString = "";
|
||||
if (ControlFlowUtils.statementContainsNakedBreak(ifStatement)) {
|
||||
breakTarget = PsiTreeUtil.getParentOfType(ifStatement,
|
||||
PsiLoopStatement.class, PsiSwitchStatement.class);
|
||||
if (breakTarget != null) {
|
||||
final PsiElement parent = breakTarget.getParent();
|
||||
if (parent instanceof PsiLabeledStatement) {
|
||||
final PsiLabeledStatement labeledStatement =
|
||||
(PsiLabeledStatement) parent;
|
||||
labelString =
|
||||
labeledStatement.getLabelIdentifier().getText();
|
||||
breakTarget = labeledStatement;
|
||||
breaksNeedRelabeled = true;
|
||||
} else {
|
||||
labelString =
|
||||
SwitchUtils.findUniqueLabelName(ifStatement,
|
||||
"label");
|
||||
breaksNeedRelabeled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiIfStatement statementToReplace = ifStatement;
|
||||
|
||||
final List<IfStatementBranch> branches =
|
||||
new ArrayList<IfStatementBranch>(20);
|
||||
while (true) {
|
||||
final PsiExpression condition = ifStatement.getCondition();
|
||||
final List<PsiExpression> labels =
|
||||
getValuesFromExpression(condition, switchExpression,
|
||||
new ArrayList());
|
||||
final PsiStatement thenBranch = ifStatement.getThenBranch();
|
||||
final IfStatementBranch ifBranch =
|
||||
new IfStatementBranch(thenBranch, false);
|
||||
if (!branches.isEmpty()) {
|
||||
extractIfComments(ifStatement, ifBranch);
|
||||
}
|
||||
extractStatementComments(thenBranch, ifBranch);
|
||||
for (final PsiExpression label : labels) {
|
||||
if (label instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression reference =
|
||||
(PsiReferenceExpression)label;
|
||||
final PsiElement referent = reference.resolve();
|
||||
if (referent instanceof PsiEnumConstant) {
|
||||
final PsiEnumConstant constant =
|
||||
(PsiEnumConstant)referent;
|
||||
final String constantName = constant.getName();
|
||||
ifBranch.addCondition(constantName);
|
||||
} else {
|
||||
final String labelText = label.getText();
|
||||
ifBranch.addCondition(labelText);
|
||||
}
|
||||
} else {
|
||||
final String labelText = label.getText();
|
||||
ifBranch.addCondition(labelText);
|
||||
}
|
||||
}
|
||||
branches.add(ifBranch);
|
||||
final PsiStatement elseBranch = ifStatement.getElseBranch();
|
||||
if (elseBranch instanceof PsiIfStatement) {
|
||||
ifStatement = (PsiIfStatement)elseBranch;
|
||||
} else if (elseBranch == null) {
|
||||
break;
|
||||
} else {
|
||||
final IfStatementBranch elseIfBranch =
|
||||
new IfStatementBranch(elseBranch, true);
|
||||
final PsiKeyword elseKeyword = ifStatement.getElseElement();
|
||||
extractIfComments(elseKeyword, elseIfBranch);
|
||||
extractStatementComments(elseBranch, elseIfBranch);
|
||||
branches.add(elseIfBranch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNls final StringBuilder switchStatementText =
|
||||
new StringBuilder();
|
||||
switchStatementText.append("switch(");
|
||||
switchStatementText.append(switchExpression.getText());
|
||||
switchStatementText.append("){");
|
||||
for (IfStatementBranch branch : branches) {
|
||||
boolean hasConflicts = false;
|
||||
for (IfStatementBranch testBranch : branches) {
|
||||
if (branch == testBranch) {
|
||||
continue;
|
||||
}
|
||||
if (branch.topLevelDeclarationsConflictWith(testBranch)) {
|
||||
hasConflicts = true;
|
||||
}
|
||||
}
|
||||
dumpBranch(branch, hasConflicts, breaksNeedRelabeled,
|
||||
labelString, switchStatementText);
|
||||
}
|
||||
switchStatementText.append('}');
|
||||
final JavaPsiFacade psiFacade =
|
||||
JavaPsiFacade.getInstance(element.getProject());
|
||||
final PsiElementFactory factory = psiFacade.getElementFactory();
|
||||
if (breaksNeedRelabeled) {
|
||||
final StringBuilder out = new StringBuilder();
|
||||
if (!(breakTarget instanceof PsiLabeledStatement)) {
|
||||
out.append(labelString);
|
||||
out.append(':');
|
||||
}
|
||||
termReplace(out, breakTarget, statementToReplace,
|
||||
switchStatementText);
|
||||
final String newStatementText = out.toString();
|
||||
final PsiStatement newStatement =
|
||||
factory.createStatementFromText(newStatementText,
|
||||
element);
|
||||
breakTarget.replace(newStatement);
|
||||
} else {
|
||||
final PsiStatement newStatement =
|
||||
factory.createStatementFromText(
|
||||
switchStatementText.toString(), element);
|
||||
statementToReplace.replace(newStatement);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T extends PsiElement> T getPrevSiblingOfType(
|
||||
@Nullable PsiElement element,
|
||||
@NotNull Class<T> aClass,
|
||||
@NotNull Class<? extends PsiElement>... stopAt) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
PsiElement sibling = element.getPrevSibling();
|
||||
while (sibling != null && !aClass.isInstance(sibling)) {
|
||||
for (Class<? extends PsiElement> stopClass : stopAt) {
|
||||
if (stopClass.isInstance(sibling)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
sibling = sibling.getPrevSibling();
|
||||
}
|
||||
return (T)sibling;
|
||||
}
|
||||
|
||||
private static void extractIfComments(PsiElement element,
|
||||
IfStatementBranch out) {
|
||||
PsiComment comment = getPrevSiblingOfType(element,
|
||||
PsiComment.class, PsiStatement.class);
|
||||
while (comment != null) {
|
||||
final PsiElement sibling = comment.getPrevSibling();
|
||||
final String commentText;
|
||||
if (sibling instanceof PsiWhiteSpace) {
|
||||
final String whiteSpaceText = sibling.getText();
|
||||
if (whiteSpaceText.startsWith("\n")) {
|
||||
commentText = whiteSpaceText.substring(1) +
|
||||
comment.getText();
|
||||
} else {
|
||||
commentText = comment.getText();
|
||||
}
|
||||
} else {
|
||||
commentText = comment.getText();
|
||||
}
|
||||
out.addComment(commentText);
|
||||
comment = getPrevSiblingOfType(comment, PsiComment.class,
|
||||
PsiStatement.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractStatementComments(PsiElement element,
|
||||
IfStatementBranch out) {
|
||||
PsiComment comment = getPrevSiblingOfType(element,
|
||||
PsiComment.class, PsiStatement.class, PsiKeyword.class);
|
||||
while (comment != null) {
|
||||
final PsiElement sibling = comment.getPrevSibling();
|
||||
final String commentText;
|
||||
if (sibling instanceof PsiWhiteSpace) {
|
||||
final String whiteSpaceText = sibling.getText();
|
||||
if (whiteSpaceText.startsWith("\n")) {
|
||||
commentText = whiteSpaceText.substring(1) +
|
||||
comment.getText();
|
||||
} else {
|
||||
commentText = comment.getText();
|
||||
}
|
||||
} else {
|
||||
commentText = comment.getText();
|
||||
}
|
||||
out.addStatementComment(commentText);
|
||||
comment = getPrevSiblingOfType(comment, PsiComment.class,
|
||||
PsiStatement.class, PsiKeyword.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static void termReplace(
|
||||
StringBuilder out, PsiElement target,
|
||||
PsiElement replace, StringBuilder stringToReplaceWith) {
|
||||
if (target.equals(replace)) {
|
||||
out.append(stringToReplaceWith);
|
||||
} else if (target.getChildren().length == 0) {
|
||||
out.append(target.getText());
|
||||
} else {
|
||||
final PsiElement[] children = target.getChildren();
|
||||
for (final PsiElement child : children) {
|
||||
termReplace(out, child, replace, stringToReplaceWith);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<PsiExpression> getValuesFromExpression(
|
||||
PsiExpression expression, PsiExpression caseExpression,
|
||||
List<PsiExpression> values) {
|
||||
if (expression instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCallExpression =
|
||||
(PsiMethodCallExpression) expression;
|
||||
final PsiExpressionList argumentList =
|
||||
methodCallExpression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
final PsiExpression argument = arguments[0];
|
||||
final PsiReferenceExpression methodExpression =
|
||||
methodCallExpression.getMethodExpression();
|
||||
final PsiExpression qualifierExpression =
|
||||
methodExpression.getQualifierExpression();
|
||||
if (EquivalenceChecker.expressionsAreEquivalent(caseExpression,
|
||||
argument)) {
|
||||
values.add(qualifierExpression);
|
||||
} else {
|
||||
values.add(argument);
|
||||
}
|
||||
} else if (expression instanceof PsiBinaryExpression) {
|
||||
final PsiBinaryExpression binaryExpression =
|
||||
(PsiBinaryExpression)expression;
|
||||
final PsiExpression lhs = binaryExpression.getLOperand();
|
||||
final PsiExpression rhs = binaryExpression.getROperand();
|
||||
final PsiJavaToken sign = binaryExpression.getOperationSign();
|
||||
final IElementType tokenType = sign.getTokenType();
|
||||
if (JavaTokenType.OROR.equals(tokenType)) {
|
||||
getValuesFromExpression(lhs, caseExpression,
|
||||
values);
|
||||
getValuesFromExpression(rhs, caseExpression,
|
||||
values);
|
||||
} else {
|
||||
if (EquivalenceChecker.expressionsAreEquivalent(
|
||||
caseExpression, rhs)) {
|
||||
values.add(lhs);
|
||||
} else {
|
||||
values.add(rhs);
|
||||
}
|
||||
}
|
||||
} else if (expression instanceof PsiParenthesizedExpression) {
|
||||
final PsiParenthesizedExpression parenthesizedExpression =
|
||||
(PsiParenthesizedExpression)expression;
|
||||
final PsiExpression contents =
|
||||
parenthesizedExpression.getExpression();
|
||||
getValuesFromExpression(contents, caseExpression, values);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private static void dumpBranch(
|
||||
IfStatementBranch branch, boolean wrap,
|
||||
boolean renameBreaks, String breakLabelName,
|
||||
@NonNls StringBuilder switchStatementText) {
|
||||
dumpComments(branch.getComments(), switchStatementText);
|
||||
if (branch.isElse()) {
|
||||
switchStatementText.append("default: ");
|
||||
} else {
|
||||
for (String label : branch.getConditions()) {
|
||||
switchStatementText.append("case ");
|
||||
switchStatementText.append(label);
|
||||
switchStatementText.append(": ");
|
||||
}
|
||||
}
|
||||
dumpComments(branch.getStatementComments(), switchStatementText);
|
||||
dumpBody(branch.getStatement(), wrap, renameBreaks, breakLabelName,
|
||||
switchStatementText);
|
||||
}
|
||||
|
||||
private static void dumpComments(List<String> comments,
|
||||
StringBuilder switchStatementText) {
|
||||
if (comments.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
switchStatementText.append('\n');
|
||||
for (String comment : comments) {
|
||||
switchStatementText.append(comment);
|
||||
switchStatementText.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpBody(
|
||||
PsiStatement bodyStatement, boolean wrap, boolean renameBreaks,
|
||||
String breakLabelName,
|
||||
@NonNls StringBuilder switchStatementText) {
|
||||
if (wrap) {
|
||||
switchStatementText.append('{');
|
||||
}
|
||||
if (bodyStatement instanceof PsiBlockStatement) {
|
||||
final PsiCodeBlock codeBlock =
|
||||
((PsiBlockStatement)bodyStatement).getCodeBlock();
|
||||
final PsiElement[] children = codeBlock.getChildren();
|
||||
//skip the first and last members, to unwrap the block
|
||||
for (int i = 1; i < children.length - 1; i++) {
|
||||
final PsiElement child = children[i];
|
||||
appendElement(switchStatementText, child, renameBreaks,
|
||||
breakLabelName);
|
||||
}
|
||||
} else {
|
||||
appendElement(switchStatementText, bodyStatement,
|
||||
renameBreaks, breakLabelName);
|
||||
}
|
||||
if (ControlFlowUtils.statementMayCompleteNormally(
|
||||
bodyStatement)) {
|
||||
switchStatementText.append("break;");
|
||||
}
|
||||
if (wrap) {
|
||||
switchStatementText.append('}');
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendElement(
|
||||
@NonNls StringBuilder switchStatementText,
|
||||
PsiElement element, boolean renameBreakElements,
|
||||
String breakLabelString) {
|
||||
final String text = element.getText();
|
||||
if (!renameBreakElements) {
|
||||
switchStatementText.append(text);
|
||||
} else if (element instanceof PsiBreakStatement) {
|
||||
final PsiIdentifier identifier =
|
||||
((PsiBreakStatement)element).getLabelIdentifier();
|
||||
if (identifier == null) {
|
||||
switchStatementText.append("break ");
|
||||
switchStatementText.append(breakLabelString);
|
||||
switchStatementText.append(';');
|
||||
} else {
|
||||
switchStatementText.append(text);
|
||||
}
|
||||
} else if (element instanceof PsiBlockStatement ||
|
||||
element instanceof PsiCodeBlock ||
|
||||
element instanceof PsiIfStatement) {
|
||||
final PsiElement[] children = element.getChildren();
|
||||
for (final PsiElement child : children) {
|
||||
appendElement(switchStatementText, child,
|
||||
renameBreakElements, breakLabelString);
|
||||
}
|
||||
} else {
|
||||
switchStatementText.append(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new IfCanBeSwitchVisitor();
|
||||
}
|
||||
|
||||
private class IfCanBeSwitchVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitIfStatement(PsiIfStatement statement) {
|
||||
super.visitIfStatement(statement);
|
||||
final PsiElement parent = statement.getParent();
|
||||
if (parent instanceof PsiIfStatement) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression switchExpression =
|
||||
SwitchUtils.getSwitchExpression(statement, minimumBranches);
|
||||
if (switchExpression == null) {
|
||||
return;
|
||||
}
|
||||
registerStatementError(statement, switchExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2003-2011 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.
|
||||
* 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.siyeh.ig.controlflow;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class IfStatementBranch{
|
||||
|
||||
private final Set<String> topLevelVariables = new HashSet<String>(3);
|
||||
private final LinkedList<String> comments = new LinkedList<String>();
|
||||
private final LinkedList<String> statementComments = new LinkedList<String>();
|
||||
private final List<String> conditions = new ArrayList<String>(3);
|
||||
private final PsiStatement statement;
|
||||
private final boolean elseBranch;
|
||||
|
||||
public IfStatementBranch(PsiStatement branch, boolean elseBranch) {
|
||||
statement = branch;
|
||||
this.elseBranch = elseBranch;
|
||||
calculateVariablesDeclared(statement);
|
||||
}
|
||||
|
||||
public void addComment(String comment){
|
||||
comments.addFirst(comment);
|
||||
}
|
||||
|
||||
public void addStatementComment(String comment) {
|
||||
statementComments.addFirst(comment);
|
||||
}
|
||||
|
||||
public void addCondition(String conditionString){
|
||||
conditions.add(conditionString);
|
||||
}
|
||||
|
||||
public PsiStatement getStatement(){
|
||||
return statement;
|
||||
}
|
||||
|
||||
public List<String> getConditions(){
|
||||
return Collections.unmodifiableList(conditions);
|
||||
}
|
||||
|
||||
public boolean isElse(){
|
||||
return elseBranch;
|
||||
}
|
||||
|
||||
public boolean topLevelDeclarationsConflictWith(
|
||||
IfStatementBranch testBranch){
|
||||
final Set<String> topLevel = testBranch.topLevelVariables;
|
||||
return intersects(topLevelVariables, topLevel);
|
||||
}
|
||||
|
||||
private static boolean intersects(Set<String> set1,
|
||||
Set<String> set2){
|
||||
for(final String s : set1){
|
||||
if(set2.contains(s)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<String> getComments() {
|
||||
return comments;
|
||||
}
|
||||
|
||||
public List<String> getStatementComments() {
|
||||
return statementComments;
|
||||
}
|
||||
|
||||
public void calculateVariablesDeclared(PsiStatement statement){
|
||||
if(statement == null){
|
||||
return;
|
||||
}
|
||||
if(statement instanceof PsiDeclarationStatement){
|
||||
final PsiDeclarationStatement declarationStatement =
|
||||
(PsiDeclarationStatement) statement;
|
||||
final PsiElement[] elements =
|
||||
declarationStatement.getDeclaredElements();
|
||||
for(PsiElement element : elements){
|
||||
final PsiVariable variable = (PsiVariable) element;
|
||||
final String varName = variable.getName();
|
||||
topLevelVariables.add(varName);
|
||||
}
|
||||
} else if(statement instanceof PsiBlockStatement){
|
||||
final PsiBlockStatement block = (PsiBlockStatement) statement;
|
||||
final PsiCodeBlock codeBlock = block.getCodeBlock();
|
||||
final PsiStatement[] statements = codeBlock.getStatements();
|
||||
for(PsiStatement statement1 : statements){
|
||||
calculateVariablesDeclared(statement1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -61,18 +61,21 @@ public class OverlyComplexBooleanExpressionInspection
|
||||
/** @noinspection PublicField*/
|
||||
public boolean m_ignorePureConjunctionsDisjunctions = true;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"overly.complex.boolean.expression.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"overly.complex.boolean.expression.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
final ButtonModel pureModel =
|
||||
m_ignoreConjunctionsDisjunctionsCheckBox.getModel();
|
||||
@@ -85,7 +88,7 @@ public class OverlyComplexBooleanExpressionInspection
|
||||
});
|
||||
final NumberFormat formatter = NumberFormat.getIntegerInstance();
|
||||
formatter.setParseIntegerOnly(true);
|
||||
m_termLimitTextField.setValue(m_limit);
|
||||
m_termLimitTextField.setValue(Integer.valueOf(m_limit));
|
||||
m_termLimitTextField.setColumns(4);
|
||||
FormattedTextFieldMacFix.apply(m_termLimitTextField);
|
||||
final Document document = m_termLimitTextField.getDocument();
|
||||
@@ -115,19 +118,22 @@ public class OverlyComplexBooleanExpressionInspection
|
||||
return m_contentPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos){
|
||||
return new ExtractMethodFix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new SwitchStatementWithTooManyBranchesVisitor();
|
||||
return new OverlyComplexBooleanExpressionVisitor();
|
||||
}
|
||||
|
||||
private class SwitchStatementWithTooManyBranchesVisitor
|
||||
private class OverlyComplexBooleanExpressionVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override public void visitBinaryExpression(
|
||||
|
||||
+7
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -37,12 +37,14 @@ public class SwitchStatementDensityInspection extends BaseInspection {
|
||||
*/
|
||||
public int m_limit = DEFAULT_DENSITY_LIMIT;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"switch.statement.density.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleIntegerFieldOptionsPanel(
|
||||
InspectionGadgetsBundle.message(
|
||||
@@ -50,6 +52,7 @@ public class SwitchStatementDensityInspection extends BaseInspection {
|
||||
"m_limit");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
final Integer intDensity = (Integer)infos[0];
|
||||
@@ -57,11 +60,12 @@ public class SwitchStatementDensityInspection extends BaseInspection {
|
||||
"switch.statement.density.problem.descriptor", intDensity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new SwitchStatementWithTooFewBranchesVisitor();
|
||||
return new SwitchStatementDensityVisitor();
|
||||
}
|
||||
|
||||
private class SwitchStatementWithTooFewBranchesVisitor
|
||||
private class SwitchStatementDensityVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override public void visitSwitchStatement(
|
||||
|
||||
+9
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -48,18 +48,21 @@ public class OverlyComplexArithmeticExpressionInspection
|
||||
arithmeticTokens.add("%");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"overly.complex.arithmetic.expression.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"overly.complex.arithmetic.expression.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleIntegerFieldOptionsPanel(
|
||||
InspectionGadgetsBundle.message(
|
||||
@@ -67,19 +70,22 @@ public class OverlyComplexArithmeticExpressionInspection
|
||||
this, "m_limit");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new ExtractMethodFix();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new SwitchStatementWithTooManyBranchesVisitor();
|
||||
return new OverlyComplexArithmeticExpressionVisitor();
|
||||
}
|
||||
|
||||
private class SwitchStatementWithTooManyBranchesVisitor
|
||||
private class OverlyComplexArithmeticExpressionVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override public void visitBinaryExpression(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -23,9 +23,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ControlFlowUtils{
|
||||
|
||||
private ControlFlowUtils(){
|
||||
super();
|
||||
}
|
||||
private ControlFlowUtils(){}
|
||||
|
||||
public static boolean statementMayCompleteNormally(
|
||||
@Nullable PsiStatement statement){
|
||||
@@ -503,6 +501,67 @@ public class ControlFlowUtils{
|
||||
return !codeBlockMayCompleteNormally(body);
|
||||
}
|
||||
|
||||
public static boolean statementContainsNakedBreak(PsiStatement statement){
|
||||
if(statement == null){
|
||||
return false;
|
||||
}
|
||||
final NakedBreakFinder breakFinder = new NakedBreakFinder();
|
||||
statement.accept(breakFinder);
|
||||
return breakFinder.breakFound();
|
||||
}
|
||||
|
||||
private static class NakedBreakFinder
|
||||
extends JavaRecursiveElementWalkingVisitor{
|
||||
|
||||
private boolean m_found = false;
|
||||
|
||||
public boolean breakFound(){
|
||||
return m_found;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (m_found) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override public void visitReferenceExpression(
|
||||
PsiReferenceExpression expression){
|
||||
}
|
||||
|
||||
@Override public void visitBreakStatement(PsiBreakStatement statement){
|
||||
if(statement.getLabelIdentifier() != null){
|
||||
return;
|
||||
}
|
||||
m_found = true;
|
||||
}
|
||||
|
||||
@Override public void visitDoWhileStatement(
|
||||
PsiDoWhileStatement statement){
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@Override public void visitForStatement(PsiForStatement statement){
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForeachStatement(PsiForeachStatement statement) {
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@Override public void visitWhileStatement(PsiWhileStatement statement){
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@Override public void visitSwitchStatement(
|
||||
PsiSwitchStatement statement){
|
||||
// don't drill down
|
||||
}
|
||||
}
|
||||
|
||||
private static class SystemExitFinder extends JavaRecursiveElementVisitor{
|
||||
|
||||
private boolean m_found = false;
|
||||
@@ -599,7 +658,6 @@ public class ControlFlowUtils{
|
||||
private String m_label = null;
|
||||
|
||||
private ContinueFinder(@NotNull PsiStatement target){
|
||||
super();
|
||||
if(target.getParent() instanceof PsiLabeledStatement){
|
||||
final PsiLabeledStatement labeledStatement =
|
||||
(PsiLabeledStatement) target.getParent();
|
||||
@@ -694,8 +752,12 @@ public class ControlFlowUtils{
|
||||
this.parameterTypeNames = parameterTypeNames;
|
||||
}
|
||||
|
||||
public boolean containsCallToMethod() {
|
||||
return containsCallToMethod;
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (containsCallToMethod) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override public void visitMethodCallExpression(
|
||||
@@ -710,6 +772,10 @@ public class ControlFlowUtils{
|
||||
}
|
||||
containsCallToMethod = true;
|
||||
}
|
||||
|
||||
public boolean containsCallToMethod() {
|
||||
return containsCallToMethod;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ContinueToAncestorFinder
|
||||
@@ -722,6 +788,14 @@ public class ControlFlowUtils{
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (found) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitContinueStatement(
|
||||
PsiContinueStatement continueStatement) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2006 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -15,17 +15,17 @@
|
||||
*/
|
||||
package com.siyeh.ig.psiutils;
|
||||
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiStatement;
|
||||
import com.intellij.psi.PsiSwitchLabelStatement;
|
||||
import com.intellij.psi.PsiSwitchStatement;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SwitchUtils{
|
||||
|
||||
private SwitchUtils(){
|
||||
super();
|
||||
}
|
||||
private SwitchUtils(){}
|
||||
|
||||
public static int calculateBranchCount(
|
||||
@NotNull PsiSwitchStatement statement){
|
||||
@@ -42,4 +42,247 @@ public class SwitchUtils{
|
||||
}
|
||||
return branches;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiExpression getSwitchExpression(PsiIfStatement statement,
|
||||
int minimumBranches){
|
||||
final PsiExpression condition = statement.getCondition();
|
||||
final LanguageLevel languageLevel =
|
||||
PsiUtil.getLanguageLevel(statement);
|
||||
final PsiExpression possibleSwitchExpression =
|
||||
determinePossibleSwitchExpressions(condition, languageLevel);
|
||||
if(possibleSwitchExpression == null){
|
||||
return null;
|
||||
}
|
||||
if (SideEffectChecker.mayHaveSideEffects(possibleSwitchExpression)) {
|
||||
return null;
|
||||
}
|
||||
int branchCount = 0;
|
||||
while(true){
|
||||
branchCount++;
|
||||
final PsiExpression caseCondition = statement.getCondition();
|
||||
if (!canBeMadeIntoCase(caseCondition, possibleSwitchExpression,
|
||||
languageLevel)) {
|
||||
break;
|
||||
}
|
||||
final PsiStatement elseBranch = statement.getElseBranch();
|
||||
if(!(elseBranch instanceof PsiIfStatement)){
|
||||
if (elseBranch != null) {
|
||||
branchCount++;
|
||||
}
|
||||
if (branchCount < minimumBranches) {
|
||||
return null;
|
||||
}
|
||||
return possibleSwitchExpression;
|
||||
}
|
||||
statement = (PsiIfStatement) elseBranch;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean canBeMadeIntoCase(
|
||||
PsiExpression expression, PsiExpression caseExpression,
|
||||
LanguageLevel languageLevel) {
|
||||
while(expression instanceof PsiParenthesizedExpression){
|
||||
final PsiParenthesizedExpression parenthesizedExpression =
|
||||
(PsiParenthesizedExpression)expression;
|
||||
expression = parenthesizedExpression.getExpression();
|
||||
}
|
||||
if (languageLevel.compareTo(LanguageLevel.JDK_1_7) >=0 ) {
|
||||
final PsiExpression stringCaseExpression =
|
||||
determinePossibleStringSwitchExpression(expression);
|
||||
if (EquivalenceChecker.expressionsAreEquivalent(caseExpression,
|
||||
stringCaseExpression)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(!(expression instanceof PsiBinaryExpression)){
|
||||
return false;
|
||||
}
|
||||
final PsiBinaryExpression binaryExpression =
|
||||
(PsiBinaryExpression) expression;
|
||||
final PsiJavaToken sign = binaryExpression.getOperationSign();
|
||||
final IElementType operation = sign.getTokenType();
|
||||
final PsiExpression lOperand = binaryExpression.getLOperand();
|
||||
final PsiExpression rhs = binaryExpression.getROperand();
|
||||
if(operation.equals(JavaTokenType.OROR)){
|
||||
return canBeMadeIntoCase(lOperand, caseExpression, languageLevel) &&
|
||||
canBeMadeIntoCase(rhs, caseExpression, languageLevel);
|
||||
} else if(operation.equals(JavaTokenType.EQEQ)){
|
||||
return (canBeCaseLabel(lOperand, languageLevel) &&
|
||||
EquivalenceChecker.expressionsAreEquivalent(
|
||||
caseExpression, rhs))
|
||||
||
|
||||
(canBeCaseLabel(rhs, languageLevel) &&
|
||||
EquivalenceChecker.expressionsAreEquivalent(
|
||||
caseExpression, lOperand));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiExpression determinePossibleSwitchExpressions(
|
||||
PsiExpression expression, LanguageLevel languageLevel){
|
||||
while(expression instanceof PsiParenthesizedExpression){
|
||||
final PsiParenthesizedExpression parenthesizedExpression =
|
||||
(PsiParenthesizedExpression)expression;
|
||||
expression = parenthesizedExpression.getExpression();
|
||||
}
|
||||
if (expression == null) {
|
||||
return null;
|
||||
}
|
||||
if (languageLevel.compareTo(LanguageLevel.JDK_1_7) >= 0) {
|
||||
final PsiExpression jdk17Expression =
|
||||
determinePossibleStringSwitchExpression(expression);
|
||||
if (jdk17Expression != null) {
|
||||
return jdk17Expression;
|
||||
}
|
||||
}
|
||||
if (!(expression instanceof PsiBinaryExpression)){
|
||||
return null;
|
||||
}
|
||||
final PsiBinaryExpression binaryExpression =
|
||||
(PsiBinaryExpression) expression;
|
||||
final PsiJavaToken sign = binaryExpression.getOperationSign();
|
||||
final IElementType operation = sign.getTokenType();
|
||||
final PsiExpression lhs = binaryExpression.getLOperand();
|
||||
final PsiExpression rhs = binaryExpression.getROperand();
|
||||
if(operation.equals(JavaTokenType.OROR)){
|
||||
return determinePossibleSwitchExpressions(lhs, languageLevel);
|
||||
} else if(operation.equals(JavaTokenType.EQEQ)){
|
||||
if(canBeCaseLabel(lhs, languageLevel)){
|
||||
return rhs;
|
||||
} else if (canBeCaseLabel(rhs, languageLevel)){
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiExpression determinePossibleStringSwitchExpression(
|
||||
PsiExpression expression) {
|
||||
if (!(expression instanceof PsiMethodCallExpression)) {
|
||||
return null;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression =
|
||||
(PsiMethodCallExpression) expression;
|
||||
final PsiReferenceExpression methodExpression =
|
||||
methodCallExpression.getMethodExpression();
|
||||
@NonNls final String referenceName =
|
||||
methodExpression.getReferenceName();
|
||||
if (!"equals".equals(referenceName)) {
|
||||
return null;
|
||||
}
|
||||
final PsiExpression qualifierExpression =
|
||||
methodExpression.getQualifierExpression();
|
||||
if (qualifierExpression == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiType type = qualifierExpression.getType();
|
||||
if (type == null || !type.equalsToText("java.lang.String")) {
|
||||
return null;
|
||||
}
|
||||
final PsiExpressionList argumentList =
|
||||
methodCallExpression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length != 1) {
|
||||
return null;
|
||||
}
|
||||
final PsiExpression argument = arguments[0];
|
||||
final PsiType argumentType = argument.getType();
|
||||
if (argumentType == null ||
|
||||
!argumentType.equalsToText("java.lang.String")) {
|
||||
return null;
|
||||
}
|
||||
if (PsiUtil.isConstantExpression(qualifierExpression)) {
|
||||
return argument;
|
||||
} else if (PsiUtil.isConstantExpression(argument)) {
|
||||
return qualifierExpression;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean canBeCaseLabel(PsiExpression expression,
|
||||
LanguageLevel languageLevel){
|
||||
if(expression == null){
|
||||
return false;
|
||||
}
|
||||
if (languageLevel.compareTo(LanguageLevel.JDK_1_5) >= 0
|
||||
&& expression instanceof PsiReferenceExpression){
|
||||
final PsiElement referent = ((PsiReference) expression).resolve();
|
||||
if(referent instanceof PsiEnumConstant){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final PsiType type = expression.getType();
|
||||
return type != null &&
|
||||
(type.equals(PsiType.INT) ||
|
||||
type.equals(PsiType.CHAR) ||
|
||||
type.equals(PsiType.LONG) ||
|
||||
type.equals(PsiType.SHORT)) &&
|
||||
PsiUtil.isConstantExpression(expression);
|
||||
}
|
||||
|
||||
public static String findUniqueLabelName(PsiStatement statement,
|
||||
@NonNls String baseName){
|
||||
PsiElement ancestor = statement;
|
||||
while(ancestor.getParent() != null){
|
||||
if(ancestor instanceof PsiMethod
|
||||
|| ancestor instanceof PsiClass
|
||||
|| ancestor instanceof PsiFile){
|
||||
break;
|
||||
}
|
||||
ancestor = ancestor.getParent();
|
||||
}
|
||||
if(!checkForLabel(baseName, ancestor)){
|
||||
return baseName;
|
||||
}
|
||||
int val = 1;
|
||||
while(true){
|
||||
final String name = baseName + val;
|
||||
if(!checkForLabel(name, ancestor)){
|
||||
return name;
|
||||
}
|
||||
val++;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkForLabel(String name, PsiElement ancestor){
|
||||
final LabelSearchVisitor visitor = new LabelSearchVisitor(name);
|
||||
ancestor.accept(visitor);
|
||||
return visitor.isUsed();
|
||||
}
|
||||
|
||||
private static class LabelSearchVisitor
|
||||
extends JavaRecursiveElementWalkingVisitor {
|
||||
|
||||
private final String m_labelName;
|
||||
private boolean m_used = false;
|
||||
|
||||
LabelSearchVisitor(String name){
|
||||
m_labelName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (m_used) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabeledStatement(PsiLabeledStatement statement){
|
||||
final PsiIdentifier labelIdentifier =
|
||||
statement.getLabelIdentifier();
|
||||
final String labelText = labelIdentifier.getText();
|
||||
if(labelText.equals(m_labelName)){
|
||||
m_used = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUsed(){
|
||||
return m_used;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports any <b>if</b> statements with which can be replaced
|
||||
by a <b>switch</b> statement. This inspection will automatically suggest string
|
||||
switches when the project language level is jdk 1.7 or higher.
|
||||
Use the text field below to indicate the minimum
|
||||
number of <b>case</b> branches the resulting <b>switch</b> statement should have.
|
||||
<small>New in 11?, Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,37 +1,37 @@
|
||||
plugin.IntentionPowerPack.description=Adds over 30 new intention actions for IDEA.
|
||||
replace.fully.qualified.name.with.import.intention.name=Replace qualified name with import
|
||||
replace.fully.qualified.name.with.import.intention.name=Replace qualified name with 'import'
|
||||
replace.fully.qualified.name.with.import.intention.family.name=Replace Qualified Name with Import
|
||||
replace.if.with.switch.intention.name=Replace if with switch
|
||||
replace.if.with.switch.intention.name=Replace 'if' with 'switch'
|
||||
replace.if.with.switch.intention.family.name=Replace If with Switch
|
||||
merge.parallel.ifs.intention.name=Merge 'if's
|
||||
merge.parallel.ifs.intention.family.name=Merge Parallel Ifs
|
||||
replace.conditional.with.if.intention.name=Replace ?: with if-else
|
||||
replace.conditional.with.if.intention.name=Replace '?:' with 'if else'
|
||||
replace.conditional.with.if.intention.family.name=Replace Conditional with If Else
|
||||
merge.else.if.intention.name=Merge else-if
|
||||
merge.else.if.intention.name=Merge 'else if'
|
||||
merge.else.if.intention.family.name=Merge Else If
|
||||
change.to.end.of.line.comment.intention.name=Replace with end-of-line comment
|
||||
change.to.end.of.line.comment.intention.family.name=Replace with End Of Line Comment
|
||||
assert.to.if.intention.name=Replace assert with if statement
|
||||
assert.to.if.intention.name=Replace 'assert' with 'if' statement
|
||||
assert.to.if.intention.family.name=Replace Assert with If Statement
|
||||
replace.equality.with.safe.equals.intention.name=Replace == with safe .equals()
|
||||
replace.equality.with.safe.equals.intention.name=Replace '==' with safe '.equals()'
|
||||
replace.equality.with.safe.equals.intention.family.name=Replace Equality with Safe Equals
|
||||
replace.for.each.loop.with.indexed.for.loop.intention.name=Replace for-each loop with indexed for loop
|
||||
replace.for.each.loop.with.iterator.for.loop.intention.name=Replace for-each loop with iterator for loop
|
||||
replace.for.each.loop.with.indexed.for.loop.intention.name=Replace 'for each' loop with indexed 'for' loop
|
||||
replace.for.each.loop.with.iterator.for.loop.intention.name=Replace 'for each' loop with iterator 'for' loop
|
||||
replace.for.each.loop.with.indexed.for.loop.intention.family.name=Replace For-each Loop with Indexed For Loop
|
||||
replace.for.each.loop.with.iterator.for.loop.intention.family.name=Replace For-each Loop with Iterator For Loop
|
||||
replace.for.loop.with.while.loop.intention.name=Replace for loop with while loop
|
||||
replace.for.loop.with.while.loop.intention.name=Replace 'for' loop with 'while' loop
|
||||
replace.for.loop.with.while.loop.intention.family.name=Replace For Loop with While Loop
|
||||
replace.while.loop.with.do.while.loop.intention.name=Replace while loop with do-while loop
|
||||
replace.while.loop.with.do.while.loop.intention.name=Replace 'while' loop with 'do while' loop
|
||||
replace.while.loop.with.do.while.loop.intention.family.name=Replace While Loop with Do While Loop
|
||||
replace.do.while.loop.with.while.loop.intention.name=Replace do-while loop with while loop
|
||||
replace.do.while.loop.with.while.loop.intention.name=Replace 'do while' loop with 'while' loop
|
||||
replace.do.while.loop.with.while.loop.intention.family.name=Replace Do While Loop with While Loop
|
||||
expand.boolean.intention.name=Expand boolean use to if-else
|
||||
expand.boolean.intention.name=Expand boolean use to 'if else'
|
||||
expand.boolean.intention.family.name=Expand Boolean
|
||||
split.else.if.intention.name=Split else-if
|
||||
split.else.if.intention.name=Split 'else if'
|
||||
split.else.if.intention.family.name=Split Else If
|
||||
join.concatenated.string.literals.intention.name=Join concatenated String literals
|
||||
join.concatenated.string.literals.intention.family.name=Join Concatenated String Literals
|
||||
replace.switch.with.if.intention.name=Replace switch with if
|
||||
replace.switch.with.if.intention.name=Replace 'switch' with 'if'
|
||||
replace.switch.with.if.intention.family.name=Replace Switch with If
|
||||
simplify.variable.intention.name=Replace with Java-style array declaration
|
||||
simplify.variable.intention.family.name=Replace with Java Style Array Declaration
|
||||
@@ -39,7 +39,7 @@ constant.expression.intention.name=Compute constant value
|
||||
constant.expression.intention.family.name=Compute Constant Value
|
||||
create.assert.intention.name=Create JUnit Assertion
|
||||
create.assert.intention.family.name=Create JUnit Assertion
|
||||
simplify.if.else.intention.name=Simplify if-else
|
||||
simplify.if.else.intention.name=Simplify 'if else'
|
||||
simplify.if.else.intention.family.name=Simplify If Else
|
||||
merge.if.or.intention.name=Merge sequential 'if's
|
||||
merge.if.or.intention.family.name=Merge Equivalent Ifs to ORed Condition
|
||||
@@ -65,7 +65,7 @@ string.to.char.intention.name=Replace string literal with character
|
||||
string.to.char.intention.family.name=Replace String with Char
|
||||
convert.integer.to.decimal.intention.name=Convert to decimal
|
||||
convert.integer.to.decimal.intention.family.name=Convert to Decimal
|
||||
create.enum.switch.branches.intention.name=Create 'switch' branches
|
||||
create.enum.switch.branches.intention.name=Create missing 'switch' branches
|
||||
create.enum.switch.branches.intention.family.name=Create Enum Switch Branches
|
||||
change.to.c.style.comment.intention.name=Replace with block comment
|
||||
change.to.c.style.comment.intention.family.name=Replace with Block Comment
|
||||
@@ -75,17 +75,17 @@ split.declaration.and.initialization.intention.name=Split into declaration and i
|
||||
split.declaration.and.initialization.intention.family.name=Split Declaration and Initialization
|
||||
char.to.string.intention.name=Replace character literal with string
|
||||
char.to.string.intention.family.name=Replace Char with String
|
||||
replace.if.with.conditional.intention.name=Replace if-else with ?:
|
||||
replace.if.with.conditional.intention.name=Replace 'if else' with '?:'
|
||||
replace.if.with.conditional.intention.family.name=Replace If Else with Conditional
|
||||
replace.equality.with.equals.intention.name=Replace == with .equals()
|
||||
replace.equality.with.equals.intention.name=Replace '==' with '.equals()'
|
||||
replace.equality.with.equals.intention.family.name=Replace Equality with Equals
|
||||
make.append.chain.into.append.sequence.intention.name=Make .append() chain into .append() sequence
|
||||
make.append.chain.into.append.sequence.intention.family.name=Make Append Chain Into Append Sequence
|
||||
detail.exceptions.intention.name=Detail exceptions
|
||||
detail.exceptions.intention.family.name=Detail Exceptions
|
||||
flip.conditional.intention.name=Flip ?:
|
||||
flip.conditional.intention.name=Flip '?:'
|
||||
flip.conditional.intention.family.name=Flip Conditional
|
||||
replace.equals.with.equality.intention.name=Replace .equals() with ==
|
||||
replace.equals.with.equality.intention.name=Replace '.equals()' with '=='
|
||||
replace.equals.with.equality.intention.family.name=Replace Equals with Equality
|
||||
replace.shift.with.multiply.intention.family.name=Replace Shift with Multiply
|
||||
demorgans.intention.family.name=DeMorgan Law
|
||||
@@ -119,9 +119,9 @@ convert.catch.to.throws.intention.name=Replace catch section with throws declara
|
||||
convert.catch.to.throws.intention.family.name=Replace Catch Section with Throws Declaration
|
||||
wrap.vararg.arguments.with.explicit.array.intention.name=Wrap vararg arguments with explicit array creation
|
||||
wrap.vararg.arguments.with.explicit.array.intention.family.name=Wrap Vararg Arguments with Explicit Array Creation
|
||||
extract.while.loop.condition.to.if.statement.intention.name=Extract condition to internal if statement
|
||||
extract.while.loop.condition.to.if.statement.intention.name=Extract condition to internal 'if' statement
|
||||
extract.while.loop.condition.to.if.statement.intention.family.name=Extract While Loop Condition to Internal If Statement
|
||||
replace.concatenation.with.format.string.intention.name=Replace + with String.format() call
|
||||
replace.concatenation.with.format.string.intention.name=Replace '+ 'with 'String.format()' call
|
||||
replace.concatenation.with.format.string.intention.family.name=Replace String Concatenation with String.format() Call
|
||||
copy.concatenated.string.to.clipboard.intention.name=Copy String concatenation text to the clipboard
|
||||
copy.concatenated.string.to.clipboard.intention.family.name=Copy String Concatenation Text to the Clipboard
|
||||
@@ -137,7 +137,7 @@ replace.assignment.with.postfix.expression.intention.family.name=Replace Assignm
|
||||
convert.j.unit3.test.case.to.j.unit4.intention.family.name=Convert JUnit3 Test Case to JUnit4
|
||||
convert.j.unit3.test.case.to.j.unit4.intention.name=Convert to JUnit4 Test Case
|
||||
if.to.assertion.intention.family.name=Replace If with Assert Statement
|
||||
if.to.assertion.intention.name=Replace if with assert statement
|
||||
if.to.assertion.intention.name=Replace 'if' with 'assert' statement
|
||||
expand.to.normal.annotation.intention.family.name=Expand Annotation to Normal Form
|
||||
expand.to.normal.annotation.name=Expand to ''{0}''
|
||||
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -181,7 +181,8 @@ public class ReplaceForEachLoopWithIndexedForLoopIntention extends Intention {
|
||||
PsiExpression expression, PsiElement context) {
|
||||
if (expression instanceof PsiMethodCallExpression ||
|
||||
expression instanceof PsiTypeCastExpression ||
|
||||
expression instanceof PsiArrayAccessExpression) {
|
||||
expression instanceof PsiArrayAccessExpression ||
|
||||
expression instanceof PsiNewExpression) {
|
||||
final String variableName = getVariableName(expression);
|
||||
return createVariable(variableName, expression, context);
|
||||
} else if (expression instanceof PsiParenthesizedExpression) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2009 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -78,14 +78,15 @@ public class BoolUtils{
|
||||
return ParenthesesUtils.stripParentheses(operand);
|
||||
}
|
||||
|
||||
public static boolean isBooleanLiteral(PsiExpression exp){
|
||||
if(exp instanceof PsiLiteralExpression){
|
||||
final PsiLiteralExpression expression = (PsiLiteralExpression) exp;
|
||||
@NonNls final String text = expression.getText();
|
||||
return PsiKeyword.TRUE.equals(text) ||
|
||||
PsiKeyword.FALSE.equals(text);
|
||||
public static boolean isBooleanLiteral(PsiExpression expression){
|
||||
if (!(expression instanceof PsiLiteralExpression)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
final PsiLiteralExpression literalExpression =
|
||||
(PsiLiteralExpression) expression;
|
||||
@NonNls final String text = literalExpression.getText();
|
||||
return PsiKeyword.TRUE.equals(text) ||
|
||||
PsiKeyword.FALSE.equals(text);
|
||||
}
|
||||
|
||||
public static String getNegatedExpressionText(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2005 Dave Griffith
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -15,15 +15,12 @@
|
||||
*/
|
||||
package com.siyeh.ipp.psiutils;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.ConstantExpressionUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
|
||||
public class ControlFlowUtils{
|
||||
|
||||
private ControlFlowUtils(){
|
||||
super();
|
||||
}
|
||||
private ControlFlowUtils(){}
|
||||
|
||||
public static boolean statementMayCompleteNormally(PsiStatement statement){
|
||||
if(statement instanceof PsiBreakStatement ||
|
||||
@@ -40,8 +37,10 @@ public class ControlFlowUtils{
|
||||
} else if(statement instanceof PsiForStatement){
|
||||
final PsiForStatement loopStatement = (PsiForStatement) statement;
|
||||
final PsiExpression test = loopStatement.getCondition();
|
||||
return test != null && !isBooleanConstant(test, false) ||
|
||||
return test != null && !isBooleanConstant(test, true) ||
|
||||
statementIsBreakTarget(loopStatement);
|
||||
} else if (statement instanceof PsiForeachStatement) {
|
||||
return true;
|
||||
} else if(statement instanceof PsiWhileStatement){
|
||||
final PsiWhileStatement loopStatement =
|
||||
(PsiWhileStatement) statement;
|
||||
@@ -144,14 +143,23 @@ public class ControlFlowUtils{
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isBooleanConstant(PsiExpression test, boolean value){
|
||||
if(!PsiUtil.isConstantExpression(test)){
|
||||
private static boolean isBooleanConstant(PsiExpression expression,
|
||||
boolean b){
|
||||
if (expression == null) {
|
||||
return false;
|
||||
}
|
||||
final Boolean constantValue =
|
||||
(Boolean) ConstantExpressionUtil.computeCastTo(test,
|
||||
PsiType.BOOLEAN);
|
||||
return constantValue != null && constantValue.booleanValue() == value;
|
||||
final Project project = expression.getProject();
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
final PsiConstantEvaluationHelper constantEvaluationHelper =
|
||||
psiFacade.getConstantEvaluationHelper();
|
||||
final Object value =
|
||||
constantEvaluationHelper.computeConstantExpression
|
||||
(expression, false);
|
||||
if (!(value instanceof Boolean)) {
|
||||
return false;
|
||||
}
|
||||
final Boolean aBoolean = (Boolean) value;
|
||||
return aBoolean.booleanValue() == b;
|
||||
}
|
||||
|
||||
private static boolean statementIsBreakTarget(PsiStatement statement){
|
||||
@@ -163,22 +171,22 @@ public class ControlFlowUtils{
|
||||
return breakFinder.breakFound();
|
||||
}
|
||||
|
||||
public static boolean statementContainsExitingBreak(PsiStatement statement){
|
||||
public static boolean statementContainsNakedBreak(PsiStatement statement){
|
||||
if(statement == null){
|
||||
return false;
|
||||
}
|
||||
final ExitingBreakFinder breakFinder = new ExitingBreakFinder();
|
||||
final NakedBreakFinder breakFinder = new NakedBreakFinder();
|
||||
statement.accept(breakFinder);
|
||||
return breakFinder.breakFound();
|
||||
}
|
||||
|
||||
private static class BreakTargetFinder extends JavaRecursiveElementWalkingVisitor{
|
||||
private static class BreakTargetFinder
|
||||
extends JavaRecursiveElementWalkingVisitor{
|
||||
|
||||
private boolean m_found = false;
|
||||
private final PsiStatement m_target;
|
||||
|
||||
private BreakTargetFinder(PsiStatement target){
|
||||
super();
|
||||
m_target = target;
|
||||
}
|
||||
|
||||
@@ -186,6 +194,14 @@ public class ControlFlowUtils{
|
||||
return m_found;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (m_found) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override public void visitReferenceExpression(
|
||||
PsiReferenceExpression expression){
|
||||
}
|
||||
@@ -203,7 +219,7 @@ public class ControlFlowUtils{
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExitingBreakFinder
|
||||
private static class NakedBreakFinder
|
||||
extends JavaRecursiveElementWalkingVisitor{
|
||||
|
||||
private boolean m_found = false;
|
||||
@@ -212,7 +228,16 @@ public class ControlFlowUtils{
|
||||
return m_found;
|
||||
}
|
||||
|
||||
@Override public void visitReferenceExpression(PsiReferenceExpression expression){
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (m_found) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override public void visitReferenceExpression(
|
||||
PsiReferenceExpression expression){
|
||||
}
|
||||
|
||||
@Override public void visitBreakStatement(PsiBreakStatement statement){
|
||||
@@ -222,7 +247,8 @@ public class ControlFlowUtils{
|
||||
m_found = true;
|
||||
}
|
||||
|
||||
@Override public void visitDoWhileStatement(PsiDoWhileStatement statement){
|
||||
@Override public void visitDoWhileStatement(
|
||||
PsiDoWhileStatement statement){
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@@ -230,11 +256,17 @@ public class ControlFlowUtils{
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForeachStatement(PsiForeachStatement statement) {
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@Override public void visitWhileStatement(PsiWhileStatement statement){
|
||||
// don't drill down
|
||||
}
|
||||
|
||||
@Override public void visitSwitchStatement(PsiSwitchStatement statement){
|
||||
@Override public void visitSwitchStatement(
|
||||
PsiSwitchStatement statement){
|
||||
// don't drill down
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2005 Dave Griffith
|
||||
*
|
||||
* 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.siyeh.ipp.psiutils;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class DeclarationUtils{
|
||||
|
||||
private DeclarationUtils(){
|
||||
super();
|
||||
}
|
||||
|
||||
public static void calculateVariablesDeclared(
|
||||
PsiStatement statement, Set<String> variablesDeclaredAtTopLevel,
|
||||
Set<String> variablesDeclaredAtLowerLevels, boolean isTopLevel){
|
||||
if(statement == null){
|
||||
return;
|
||||
}
|
||||
if(statement instanceof PsiBreakStatement ||
|
||||
statement instanceof PsiExpressionStatement ||
|
||||
statement instanceof PsiContinueStatement ||
|
||||
statement instanceof PsiThrowStatement ||
|
||||
statement instanceof PsiExpressionListStatement ||
|
||||
statement instanceof PsiAssertStatement ||
|
||||
statement instanceof PsiReturnStatement){
|
||||
} else if(statement instanceof PsiDeclarationStatement){
|
||||
final PsiDeclarationStatement declStatement =
|
||||
(PsiDeclarationStatement) statement;
|
||||
final PsiElement[] elements = declStatement.getDeclaredElements();
|
||||
for(PsiElement element : elements){
|
||||
final PsiVariable var = (PsiVariable) element;
|
||||
final String varName = var.getName();
|
||||
if(isTopLevel){
|
||||
variablesDeclaredAtTopLevel.add(varName);
|
||||
} else{
|
||||
variablesDeclaredAtLowerLevels.add(varName);
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof PsiForStatement){
|
||||
final PsiForStatement loopStatement = (PsiForStatement) statement;
|
||||
final PsiStatement initialization =
|
||||
loopStatement.getInitialization();
|
||||
calculateVariablesDeclared(initialization,
|
||||
variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
final PsiStatement update = loopStatement.getUpdate();
|
||||
calculateVariablesDeclared(update, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
final PsiStatement body = loopStatement.getBody();
|
||||
calculateVariablesDeclared(body, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
} else if(statement instanceof PsiWhileStatement){
|
||||
final PsiWhileStatement loopStatement =
|
||||
(PsiWhileStatement) statement;
|
||||
final PsiStatement body = loopStatement.getBody();
|
||||
calculateVariablesDeclared(body, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
} else if(statement instanceof PsiDoWhileStatement){
|
||||
final PsiDoWhileStatement loopStatement =
|
||||
(PsiDoWhileStatement) statement;
|
||||
final PsiStatement body = loopStatement.getBody();
|
||||
calculateVariablesDeclared(body, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
} else if(statement instanceof PsiSynchronizedStatement){
|
||||
final PsiSynchronizedStatement syncStatement =
|
||||
(PsiSynchronizedStatement) statement;
|
||||
final PsiCodeBlock body = syncStatement.getBody();
|
||||
calculateVariablesDeclaredInCodeBlock(
|
||||
body, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
} else if(statement instanceof PsiBlockStatement){
|
||||
final PsiBlockStatement block = (PsiBlockStatement) statement;
|
||||
final PsiCodeBlock codeBlock = block.getCodeBlock();
|
||||
calculateVariablesDeclaredInCodeBlock(
|
||||
codeBlock, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, isTopLevel);
|
||||
} else if(statement instanceof PsiLabeledStatement){
|
||||
final PsiLabeledStatement labeledStatement =
|
||||
(PsiLabeledStatement) statement;
|
||||
final PsiStatement body = labeledStatement.getStatement();
|
||||
calculateVariablesDeclared(body, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
} else if(statement instanceof PsiIfStatement){
|
||||
final PsiIfStatement ifStatement = (PsiIfStatement) statement;
|
||||
final PsiStatement thenBranch = ifStatement.getThenBranch();
|
||||
calculateVariablesDeclared(thenBranch, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
final PsiStatement elseBranch = ifStatement.getElseBranch();
|
||||
calculateVariablesDeclared(elseBranch, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
} else if(statement instanceof PsiTryStatement){
|
||||
final PsiTryStatement tryStatement = (PsiTryStatement) statement;
|
||||
final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
|
||||
calculateVariablesDeclaredInCodeBlock(
|
||||
tryBlock, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
calculateVariablesDeclaredInCodeBlock(
|
||||
tryBlock, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
|
||||
if(finallyBlock != null){
|
||||
calculateVariablesDeclaredInCodeBlock(
|
||||
finallyBlock, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
}
|
||||
final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks();
|
||||
for(PsiCodeBlock catchBlock : catchBlocks){
|
||||
calculateVariablesDeclaredInCodeBlock(
|
||||
catchBlock, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
}
|
||||
} else if(statement instanceof PsiSwitchStatement){
|
||||
final PsiSwitchStatement switchStatement =
|
||||
(PsiSwitchStatement) statement;
|
||||
final PsiCodeBlock body = switchStatement.getBody();
|
||||
calculateVariablesDeclaredInCodeBlock(
|
||||
body, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateVariablesDeclaredInCodeBlock(
|
||||
PsiCodeBlock block, Set<String> variablesDeclaredAtTopLevel,
|
||||
Set<String>variablesDeclaredAtLowerLevels, boolean isTopLevel){
|
||||
if(block == null){
|
||||
return;
|
||||
}
|
||||
final PsiStatement[] statements = block.getStatements();
|
||||
for(PsiStatement statement : statements){
|
||||
calculateVariablesDeclared(
|
||||
statement, variablesDeclaredAtTopLevel,
|
||||
variablesDeclaredAtLowerLevels, isTopLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -15,21 +15,23 @@
|
||||
*/
|
||||
package com.siyeh.ipp.switchtoif;
|
||||
|
||||
import com.intellij.psi.PsiStatement;
|
||||
import com.intellij.psi.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class IfStatementBranch{
|
||||
|
||||
private Set<String> m_topLevelVariables = new HashSet<String>(3);
|
||||
private Set<String> m_innerVariables = new HashSet<String>(3);
|
||||
private final Set<String> topLevelVariables = new HashSet<String>(3);
|
||||
private final LinkedList<String> comments = new LinkedList<String>();
|
||||
private final LinkedList<String> statementComments = new LinkedList<String>();
|
||||
private final List<String> m_conditions = new ArrayList<String>(3);
|
||||
private PsiStatement m_statement = null;
|
||||
private boolean m_else = false;
|
||||
private final List<String> conditions = new ArrayList<String>(3);
|
||||
private final PsiStatement statement;
|
||||
private final boolean elseBranch;
|
||||
|
||||
public IfStatementBranch() {
|
||||
public IfStatementBranch(PsiStatement branch, boolean elseBranch) {
|
||||
statement = branch;
|
||||
this.elseBranch = elseBranch;
|
||||
calculateVariablesDeclared(statement);
|
||||
}
|
||||
|
||||
public void addComment(String comment){
|
||||
@@ -41,58 +43,31 @@ class IfStatementBranch{
|
||||
}
|
||||
|
||||
public void addCondition(String conditionString){
|
||||
m_conditions.add(conditionString);
|
||||
}
|
||||
|
||||
public void setStatement(PsiStatement statement){
|
||||
m_statement = statement;
|
||||
conditions.add(conditionString);
|
||||
}
|
||||
|
||||
public PsiStatement getStatement(){
|
||||
return m_statement;
|
||||
return statement;
|
||||
}
|
||||
|
||||
public List<String> getConditions(){
|
||||
return Collections.unmodifiableList(m_conditions);
|
||||
return Collections.unmodifiableList(conditions);
|
||||
}
|
||||
|
||||
public boolean isElse(){
|
||||
return m_else;
|
||||
return elseBranch;
|
||||
}
|
||||
|
||||
public void setElse(){
|
||||
m_else = true;
|
||||
}
|
||||
|
||||
public void setTopLevelVariables(Set<String> topLevelVariables){
|
||||
m_topLevelVariables = new HashSet<String>(topLevelVariables);
|
||||
}
|
||||
|
||||
public void setInnerVariables(Set<String> innerVariables){
|
||||
m_innerVariables = new HashSet<String>(innerVariables);
|
||||
}
|
||||
|
||||
private Set<String> getTopLevelVariables(){
|
||||
return Collections.unmodifiableSet(m_topLevelVariables);
|
||||
}
|
||||
|
||||
private Set<String> getInnerVariables(){
|
||||
return Collections.unmodifiableSet(m_innerVariables);
|
||||
}
|
||||
|
||||
public boolean topLevelDeclarationsConfictWith(
|
||||
public boolean topLevelDeclarationsConflictWith(
|
||||
IfStatementBranch testBranch){
|
||||
final Set<String> innerVariables = testBranch.getInnerVariables();
|
||||
final Set<String> topLevel = testBranch.getTopLevelVariables();
|
||||
return hasNonEmptyIntersection(m_topLevelVariables, topLevel) ||
|
||||
hasNonEmptyIntersection(m_topLevelVariables,
|
||||
innerVariables);
|
||||
final Set<String> topLevel = testBranch.topLevelVariables;
|
||||
return intersects(topLevelVariables, topLevel);
|
||||
}
|
||||
|
||||
private static boolean hasNonEmptyIntersection(Set<String> set1,
|
||||
Set<String> set2){
|
||||
for(final String set1Element : set1){
|
||||
if(set2.contains(set1Element)){
|
||||
private static boolean intersects(Set<String> set1,
|
||||
Set<String> set2){
|
||||
for(final String s : set1){
|
||||
if(set2.contains(s)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -106,4 +81,28 @@ class IfStatementBranch{
|
||||
public List<String> getStatementComments() {
|
||||
return statementComments;
|
||||
}
|
||||
|
||||
public void calculateVariablesDeclared(PsiStatement statement){
|
||||
if(statement == null){
|
||||
return;
|
||||
}
|
||||
if(statement instanceof PsiDeclarationStatement){
|
||||
final PsiDeclarationStatement declarationStatement =
|
||||
(PsiDeclarationStatement) statement;
|
||||
final PsiElement[] elements =
|
||||
declarationStatement.getDeclaredElements();
|
||||
for(PsiElement element : elements){
|
||||
final PsiVariable variable = (PsiVariable) element;
|
||||
final String varName = variable.getName();
|
||||
topLevelVariables.add(varName);
|
||||
}
|
||||
} else if(statement instanceof PsiBlockStatement){
|
||||
final PsiBlockStatement block = (PsiBlockStatement) statement;
|
||||
final PsiCodeBlock codeBlock = block.getCodeBlock();
|
||||
final PsiStatement[] statements = codeBlock.getStatements();
|
||||
for(PsiStatement statement1 : statements){
|
||||
calculateVariablesDeclared(statement1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -40,6 +40,6 @@ class IfToSwitchPredicate implements PsiElementPredicate{
|
||||
if(ErrorUtil.containsError(statement)){
|
||||
return false;
|
||||
}
|
||||
return CaseUtil.getCaseExpression(statement) != null;
|
||||
return SwitchUtils.getSwitchExpression(statement) != null;
|
||||
}
|
||||
}
|
||||
+112
-163
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -17,20 +17,18 @@ package com.siyeh.ipp.switchtoif;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.ipp.base.Intention;
|
||||
import com.siyeh.ipp.base.PsiElementPredicate;
|
||||
import com.siyeh.ipp.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ipp.psiutils.DeclarationUtils;
|
||||
import com.siyeh.ipp.psiutils.EquivalenceChecker;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ReplaceIfWithSwitchIntention extends Intention {
|
||||
|
||||
@@ -51,51 +49,44 @@ public class ReplaceIfWithSwitchIntention extends Intention {
|
||||
boolean breaksNeedRelabeled = false;
|
||||
PsiStatement breakTarget = null;
|
||||
String labelString = "";
|
||||
if (ControlFlowUtils.statementContainsExitingBreak(ifStatement)) {
|
||||
// what a pain.
|
||||
PsiElement ancestor = ifStatement.getParent();
|
||||
while (ancestor != null) {
|
||||
if (ancestor instanceof PsiForStatement ||
|
||||
ancestor instanceof PsiDoWhileStatement ||
|
||||
ancestor instanceof PsiWhileStatement ||
|
||||
ancestor instanceof PsiSwitchStatement) {
|
||||
breakTarget = (PsiStatement)ancestor;
|
||||
break;
|
||||
}
|
||||
ancestor = ancestor.getParent();
|
||||
}
|
||||
if (ControlFlowUtils.statementContainsNakedBreak(ifStatement)) {
|
||||
breakTarget = PsiTreeUtil.getParentOfType(ifStatement,
|
||||
PsiLoopStatement.class, PsiSwitchStatement.class);
|
||||
if (breakTarget != null) {
|
||||
labelString = CaseUtil.findUniqueLabel(ifStatement, "Label");
|
||||
breaksNeedRelabeled = true;
|
||||
final PsiElement parent = breakTarget.getParent();
|
||||
if (parent instanceof PsiLabeledStatement) {
|
||||
final PsiLabeledStatement labeledStatement =
|
||||
(PsiLabeledStatement) parent;
|
||||
labelString =
|
||||
labeledStatement.getLabelIdentifier().getText();
|
||||
breakTarget = labeledStatement;
|
||||
breaksNeedRelabeled = true;
|
||||
} else {
|
||||
labelString = SwitchUtils.findUniqueLabelName(ifStatement,
|
||||
"label");
|
||||
breaksNeedRelabeled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiIfStatement statementToReplace = ifStatement;
|
||||
final PsiExpression caseExpression =
|
||||
CaseUtil.getCaseExpression(ifStatement);
|
||||
assert caseExpression != null;
|
||||
final PsiExpression switchExpression =
|
||||
SwitchUtils.getSwitchExpression(ifStatement);
|
||||
assert switchExpression != null;
|
||||
|
||||
final List<IfStatementBranch> branches =
|
||||
new ArrayList<IfStatementBranch>(20);
|
||||
while (true) {
|
||||
final Set<String> topLevelVariables = new HashSet<String>(5);
|
||||
final Set<String> innerVariables = new HashSet<String>(5);
|
||||
final PsiExpression condition = ifStatement.getCondition();
|
||||
final List<PsiExpression> labels =
|
||||
getValuesFromExpression(condition, caseExpression,
|
||||
getValuesFromExpression(condition, switchExpression,
|
||||
new ArrayList());
|
||||
final PsiStatement thenBranch = ifStatement.getThenBranch();
|
||||
DeclarationUtils.calculateVariablesDeclared(thenBranch,
|
||||
topLevelVariables,
|
||||
innerVariables,
|
||||
true);
|
||||
final IfStatementBranch ifBranch = new IfStatementBranch();
|
||||
final IfStatementBranch ifBranch =
|
||||
new IfStatementBranch(thenBranch, false);
|
||||
if (!branches.isEmpty()) {
|
||||
extractIfComments(ifStatement, ifBranch);
|
||||
}
|
||||
ifBranch.setInnerVariables(innerVariables);
|
||||
ifBranch.setTopLevelVariables(topLevelVariables);
|
||||
extractStatementComments(thenBranch, ifBranch);
|
||||
ifBranch.setStatement(thenBranch);
|
||||
for (final PsiExpression label : labels) {
|
||||
if (label instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression reference =
|
||||
@@ -116,26 +107,18 @@ public class ReplaceIfWithSwitchIntention extends Intention {
|
||||
}
|
||||
}
|
||||
branches.add(ifBranch);
|
||||
final PsiStatement elseBranch = ifStatement.getElseBranch();
|
||||
|
||||
final PsiStatement elseBranch = ifStatement.getElseBranch();
|
||||
if (elseBranch instanceof PsiIfStatement) {
|
||||
ifStatement = (PsiIfStatement)elseBranch;
|
||||
} else if (elseBranch == null) {
|
||||
break;
|
||||
} else {
|
||||
final Set<String> elseTopLevelVariables = new HashSet<String>(5);
|
||||
final Set<String> elseInnerVariables = new HashSet<String>(5);
|
||||
DeclarationUtils.calculateVariablesDeclared(
|
||||
elseBranch, elseTopLevelVariables, elseInnerVariables,
|
||||
true);
|
||||
final IfStatementBranch elseIfBranch = new IfStatementBranch();
|
||||
final IfStatementBranch elseIfBranch =
|
||||
new IfStatementBranch(elseBranch, true);
|
||||
final PsiKeyword elseKeyword = ifStatement.getElseElement();
|
||||
extractIfComments(elseKeyword, elseIfBranch);
|
||||
extractStatementComments(elseBranch, elseIfBranch);
|
||||
elseIfBranch.setInnerVariables(elseInnerVariables);
|
||||
elseIfBranch.setTopLevelVariables(elseTopLevelVariables);
|
||||
elseIfBranch.setElse();
|
||||
elseIfBranch.setStatement(elseBranch);
|
||||
branches.add(elseIfBranch);
|
||||
break;
|
||||
}
|
||||
@@ -144,36 +127,20 @@ public class ReplaceIfWithSwitchIntention extends Intention {
|
||||
@NonNls final StringBuilder switchStatementText =
|
||||
new StringBuilder();
|
||||
switchStatementText.append("switch(");
|
||||
switchStatementText.append(caseExpression.getText());
|
||||
switchStatementText.append(')');
|
||||
switchStatementText.append('{');
|
||||
switchStatementText.append(switchExpression.getText());
|
||||
switchStatementText.append("){");
|
||||
for (IfStatementBranch branch : branches) {
|
||||
boolean hasConflicts = false;
|
||||
for (IfStatementBranch testBranch : branches) {
|
||||
if (branch.topLevelDeclarationsConfictWith(testBranch)) {
|
||||
if (branch == testBranch) {
|
||||
continue;
|
||||
}
|
||||
if (branch.topLevelDeclarationsConflictWith(testBranch)) {
|
||||
hasConflicts = true;
|
||||
}
|
||||
}
|
||||
|
||||
final PsiStatement branchStatement = branch.getStatement();
|
||||
if (branch.isElse()) {
|
||||
final List<String> comments = branch.getComments();
|
||||
final List<String> statementComments =
|
||||
branch.getStatementComments();
|
||||
dumpDefaultBranch(switchStatementText, comments,
|
||||
branchStatement, statementComments,
|
||||
hasConflicts,
|
||||
breaksNeedRelabeled, labelString);
|
||||
} else {
|
||||
final List<String> conditions = branch.getConditions();
|
||||
final List<String> comments = branch.getComments();
|
||||
final List<String> statementComments =
|
||||
branch.getStatementComments();
|
||||
dumpBranch(switchStatementText,
|
||||
comments, conditions, statementComments,
|
||||
branchStatement, hasConflicts, breaksNeedRelabeled,
|
||||
labelString);
|
||||
}
|
||||
dumpBranch(branch, hasConflicts, breaksNeedRelabeled, labelString,
|
||||
switchStatementText);
|
||||
}
|
||||
switchStatementText.append('}');
|
||||
final JavaPsiFacade psiFacade =
|
||||
@@ -181,10 +148,12 @@ public class ReplaceIfWithSwitchIntention extends Intention {
|
||||
final PsiElementFactory factory = psiFacade.getElementFactory();
|
||||
if (breaksNeedRelabeled) {
|
||||
final StringBuilder out = new StringBuilder();
|
||||
out.append(labelString);
|
||||
out.append(':');
|
||||
termReplace(out, breakTarget, statementToReplace,
|
||||
switchStatementText);
|
||||
if (!(breakTarget instanceof PsiLabeledStatement)) {
|
||||
out.append(labelString);
|
||||
out.append(':');
|
||||
}
|
||||
termReplace(breakTarget, statementToReplace, switchStatementText,
|
||||
out);
|
||||
final String newStatementText = out.toString();
|
||||
final PsiStatement newStatement =
|
||||
factory.createStatementFromText(newStatementText, element);
|
||||
@@ -266,17 +235,16 @@ public class ReplaceIfWithSwitchIntention extends Intention {
|
||||
}
|
||||
|
||||
private static void termReplace(
|
||||
StringBuilder out, PsiElement target,
|
||||
PsiElement replace, StringBuilder stringToReplaceWith) {
|
||||
PsiElement target, PsiElement replace,
|
||||
StringBuilder stringToReplaceWith, StringBuilder out) {
|
||||
if (target.equals(replace)) {
|
||||
out.append(stringToReplaceWith);
|
||||
} else if (target.getChildren().length == 0) {
|
||||
final String text = target.getText();
|
||||
out.append(text);
|
||||
out.append(target.getText());
|
||||
} else {
|
||||
final PsiElement[] children = target.getChildren();
|
||||
for (final PsiElement child : children) {
|
||||
termReplace(out, child, replace, stringToReplaceWith);
|
||||
termReplace(child, replace, stringToReplaceWith, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,128 +290,109 @@ public class ReplaceIfWithSwitchIntention extends Intention {
|
||||
}
|
||||
}
|
||||
} else if (expression instanceof PsiParenthesizedExpression) {
|
||||
final PsiParenthesizedExpression parenExpression =
|
||||
final PsiParenthesizedExpression parenthesizedExpression =
|
||||
(PsiParenthesizedExpression)expression;
|
||||
final PsiExpression contents = parenExpression.getExpression();
|
||||
final PsiExpression contents =
|
||||
parenthesizedExpression.getExpression();
|
||||
getValuesFromExpression(contents, caseExpression, values);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private static void dumpBranch(StringBuilder switchStatementString,
|
||||
List<String> comments,
|
||||
List<String> labels,
|
||||
List<String> statementComments,
|
||||
PsiStatement body,
|
||||
boolean wrap, boolean renameBreaks,
|
||||
String breakLabelName) {
|
||||
dumpComments(switchStatementString, comments);
|
||||
dumpLabels(switchStatementString, labels);
|
||||
dumpComments(switchStatementString, statementComments);
|
||||
dumpBody(switchStatementString, body, wrap, renameBreaks,
|
||||
breakLabelName);
|
||||
private static void dumpBranch(IfStatementBranch branch,
|
||||
boolean wrap,
|
||||
boolean renameBreaks,
|
||||
String breakLabelName,
|
||||
StringBuilder switchStatementText) {
|
||||
dumpComments(branch.getComments(), switchStatementText);
|
||||
if (branch.isElse()) {
|
||||
switchStatementText.append("default: ");
|
||||
} else {
|
||||
for (String label : branch.getConditions()) {
|
||||
switchStatementText.append("case ");
|
||||
switchStatementText.append(label);
|
||||
switchStatementText.append(": ");
|
||||
}
|
||||
}
|
||||
dumpComments(branch.getStatementComments(), switchStatementText);
|
||||
dumpBody(branch.getStatement(), wrap, renameBreaks, breakLabelName,
|
||||
switchStatementText
|
||||
);
|
||||
}
|
||||
|
||||
private static void dumpComments(StringBuilder switchStatementString,
|
||||
List<String> comments) {
|
||||
private static void dumpComments(List<String> comments,
|
||||
StringBuilder switchStatementText) {
|
||||
if (!comments.isEmpty()) {
|
||||
switchStatementString.append('\n');
|
||||
switchStatementText.append('\n');
|
||||
for (String comment : comments) {
|
||||
switchStatementString.append(comment);
|
||||
switchStatementString.append('\n');
|
||||
switchStatementText.append(comment);
|
||||
switchStatementText.append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpDefaultBranch(
|
||||
@NonNls StringBuilder switchStatementString,
|
||||
List<String> comments, PsiStatement body,
|
||||
List<String> statementComments, boolean wrap,
|
||||
boolean renameBreaks, String breakLabelName) {
|
||||
dumpComments(switchStatementString, comments);
|
||||
switchStatementString.append("default: ");
|
||||
dumpComments(switchStatementString, statementComments);
|
||||
dumpBody(switchStatementString, body, wrap, renameBreaks,
|
||||
breakLabelName);
|
||||
}
|
||||
|
||||
private static void dumpLabels(@NonNls StringBuilder switchStatementString,
|
||||
List<String> labels) {
|
||||
for (String label : labels) {
|
||||
switchStatementString.append("case ");
|
||||
switchStatementString.append(label);
|
||||
switchStatementString.append(": ");
|
||||
private static void dumpBody(PsiStatement bodyStatement,
|
||||
boolean wrap,
|
||||
boolean renameBreaks,
|
||||
String breakLabelName,
|
||||
@NonNls StringBuilder switchStatementText) {
|
||||
if (wrap) {
|
||||
switchStatementText.append('{');
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpBody(@NonNls StringBuilder switchStatementString,
|
||||
PsiStatement bodyStatement, boolean wrap,
|
||||
boolean renameBreaks, String breakLabelName) {
|
||||
if (bodyStatement instanceof PsiBlockStatement) {
|
||||
if (wrap) {
|
||||
appendElement(switchStatementString, bodyStatement,
|
||||
renameBreaks, breakLabelName);
|
||||
} else {
|
||||
final PsiCodeBlock codeBlock =
|
||||
((PsiBlockStatement)bodyStatement).getCodeBlock();
|
||||
final PsiElement[] children = codeBlock.getChildren();
|
||||
//skip the first and last members, to unwrap the block
|
||||
for (int i = 1; i < children.length - 1; i++) {
|
||||
final PsiElement child = children[i];
|
||||
appendElement(switchStatementString, child, renameBreaks,
|
||||
breakLabelName);
|
||||
}
|
||||
final PsiCodeBlock codeBlock =
|
||||
((PsiBlockStatement)bodyStatement).getCodeBlock();
|
||||
final PsiElement[] children = codeBlock.getChildren();
|
||||
//skip the first and last members, to unwrap the block
|
||||
for (int i = 1; i < children.length - 1; i++) {
|
||||
final PsiElement child = children[i];
|
||||
appendElement(child, renameBreaks, breakLabelName,
|
||||
switchStatementText
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (wrap) {
|
||||
switchStatementString.append('{');
|
||||
appendElement(switchStatementString, bodyStatement,
|
||||
renameBreaks, breakLabelName);
|
||||
switchStatementString.append('}');
|
||||
} else {
|
||||
appendElement(switchStatementString, bodyStatement,
|
||||
renameBreaks, breakLabelName);
|
||||
}
|
||||
appendElement(bodyStatement, renameBreaks, breakLabelName,
|
||||
switchStatementText
|
||||
);
|
||||
}
|
||||
if (ControlFlowUtils.statementMayCompleteNormally(bodyStatement)) {
|
||||
switchStatementString.append("break; ");
|
||||
if (ControlFlowUtils.statementMayCompleteNormally(
|
||||
bodyStatement)) {
|
||||
switchStatementText.append("break;");
|
||||
}
|
||||
if (wrap) {
|
||||
switchStatementText.append('}');
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendElement(
|
||||
@NonNls StringBuilder switchStatementString,
|
||||
PsiElement element, boolean renameBreakElements,
|
||||
String breakLabelString) {
|
||||
private static void appendElement(PsiElement element,
|
||||
boolean renameBreakElements,
|
||||
String breakLabelString,
|
||||
@NonNls StringBuilder switchStatementText) {
|
||||
final String text = element.getText();
|
||||
if (!renameBreakElements) {
|
||||
switchStatementString.append(text);
|
||||
switchStatementText.append(text);
|
||||
} else if (element instanceof PsiBreakStatement) {
|
||||
final PsiBreakStatement breakStatement =
|
||||
(PsiBreakStatement) element;
|
||||
final PsiIdentifier identifier =
|
||||
((PsiBreakStatement)element).getLabelIdentifier();
|
||||
breakStatement.getLabelIdentifier();
|
||||
if (identifier == null) {
|
||||
switchStatementString.append("break ");
|
||||
switchStatementString.append(breakLabelString);
|
||||
switchStatementString.append(';');
|
||||
switchStatementText.append("break ");
|
||||
switchStatementText.append(breakLabelString);
|
||||
switchStatementText.append(';');
|
||||
} else {
|
||||
final String identifierText = identifier.getText();
|
||||
if ("".equals(identifierText)) {
|
||||
switchStatementString.append("break ");
|
||||
switchStatementString.append(breakLabelString);
|
||||
switchStatementString.append(';');
|
||||
} else {
|
||||
switchStatementString.append(text);
|
||||
}
|
||||
switchStatementText.append(text);
|
||||
}
|
||||
} else if (element instanceof PsiBlockStatement ||
|
||||
element instanceof PsiCodeBlock ||
|
||||
element instanceof PsiIfStatement) {
|
||||
final PsiElement[] children = element.getChildren();
|
||||
for (final PsiElement child : children) {
|
||||
appendElement(switchStatementString, child, renameBreakElements,
|
||||
breakLabelString);
|
||||
appendElement(child, renameBreakElements, breakLabelString,
|
||||
switchStatementText);
|
||||
}
|
||||
} else {
|
||||
switchStatementString.append(text);
|
||||
switchStatementText.append(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-63
@@ -89,15 +89,6 @@ public class ReplaceSwitchWithIfIntention extends Intention {
|
||||
if (body == null) {
|
||||
return;
|
||||
}
|
||||
final PsiStatement[] statements = body.getStatements();
|
||||
boolean renameBreaks = false;
|
||||
for (int i = 1; i < statements.length - 1; i++) {
|
||||
if (CaseUtil.containsHiddenBreak(statements[i])) {
|
||||
renameBreaks = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final List<SwitchStatementBranch> openBranches =
|
||||
new ArrayList<SwitchStatementBranch>();
|
||||
final Set<PsiLocalVariable> declaredVariables =
|
||||
@@ -161,12 +152,6 @@ public class ReplaceSwitchWithIfIntention extends Intention {
|
||||
}
|
||||
}
|
||||
final StringBuilder ifStatementText = new StringBuilder();
|
||||
String breakLabel = null;
|
||||
if (renameBreaks) {
|
||||
breakLabel = CaseUtil.findUniqueLabel(switchStatement, "Label");
|
||||
ifStatementText.append(breakLabel);
|
||||
ifStatementText.append(':');
|
||||
}
|
||||
boolean firstBranch = true;
|
||||
SwitchStatementBranch defaultBranch = null;
|
||||
for (SwitchStatementBranch branch : allBranches) {
|
||||
@@ -177,8 +162,8 @@ public class ReplaceSwitchWithIfIntention extends Intention {
|
||||
final List<PsiElement> bodyElements = branch.getBodyElements();
|
||||
final Set<PsiLocalVariable> pendingVariableDeclarations =
|
||||
branch.getPendingVariableDeclarations();
|
||||
dumpBranch(expressionText, caseValues, bodyElements, breakLabel,
|
||||
pendingVariableDeclarations, firstBranch, renameBreaks,
|
||||
dumpBranch(expressionText, caseValues, bodyElements,
|
||||
pendingVariableDeclarations, firstBranch,
|
||||
isSwitchOnString, ifStatementText);
|
||||
firstBranch = false;
|
||||
}
|
||||
@@ -188,9 +173,8 @@ public class ReplaceSwitchWithIfIntention extends Intention {
|
||||
defaultBranch.getBodyElements();
|
||||
final Set<PsiLocalVariable> pendingVariableDeclarations =
|
||||
defaultBranch.getPendingVariableDeclarations();
|
||||
dumpDefaultBranch(bodyElements, breakLabel,
|
||||
pendingVariableDeclarations, firstBranch, renameBreaks,
|
||||
ifStatementText);
|
||||
dumpDefaultBranch(bodyElements, pendingVariableDeclarations,
|
||||
firstBranch, ifStatementText);
|
||||
}
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
final PsiElementFactory factory = psiFacade.getElementFactory();
|
||||
@@ -244,28 +228,26 @@ public class ReplaceSwitchWithIfIntention extends Intention {
|
||||
|
||||
private static void dumpBranch(
|
||||
String expressionText, List<String> caseValues,
|
||||
List<PsiElement> bodyStatements, String breakLabel,
|
||||
List<PsiElement> bodyStatements,
|
||||
Set<PsiLocalVariable> variables, boolean firstBranch,
|
||||
boolean renameBreaks, boolean useEquals,
|
||||
boolean useEquals,
|
||||
@NonNls StringBuilder ifStatementString) {
|
||||
if (!firstBranch) {
|
||||
ifStatementString.append("else ");
|
||||
}
|
||||
dumpCaseValues(expressionText, caseValues, useEquals,
|
||||
ifStatementString);
|
||||
dumpBody(bodyStatements, breakLabel, variables, renameBreaks,
|
||||
ifStatementString);
|
||||
dumpBody(bodyStatements, variables, ifStatementString);
|
||||
}
|
||||
|
||||
private static void dumpDefaultBranch(
|
||||
List<PsiElement> bodyStatements, String breakLabel,
|
||||
List<PsiElement> bodyStatements,
|
||||
Set<PsiLocalVariable> variables, boolean firstBranch,
|
||||
boolean renameBreaks, @NonNls StringBuilder ifStatementString) {
|
||||
@NonNls StringBuilder ifStatementString) {
|
||||
if (!firstBranch) {
|
||||
ifStatementString.append("else ");
|
||||
}
|
||||
dumpBody(bodyStatements, breakLabel, variables, renameBreaks,
|
||||
ifStatementString);
|
||||
dumpBody(bodyStatements, variables, ifStatementString);
|
||||
}
|
||||
|
||||
private static void dumpCaseValues(
|
||||
@@ -291,13 +273,12 @@ public class ReplaceSwitchWithIfIntention extends Intention {
|
||||
ifStatementString.append(')');
|
||||
}
|
||||
|
||||
private static void dumpBody(
|
||||
List<PsiElement> bodyStatements, String breakLabel,
|
||||
Set<PsiLocalVariable> variables, boolean renameBreaks,
|
||||
@NonNls StringBuilder ifStatementString) {
|
||||
private static void dumpBody(List<PsiElement> bodyStatements,
|
||||
Set<PsiLocalVariable> variables,
|
||||
@NonNls StringBuilder ifStatementString) {
|
||||
ifStatementString.append('{');
|
||||
for (PsiLocalVariable variable : variables) {
|
||||
if (CaseUtil.isUsedByStatementList(variable, bodyStatements)) {
|
||||
if (SwitchUtils.isUsedByStatementList(variable, bodyStatements)) {
|
||||
final PsiType varType = variable.getType();
|
||||
ifStatementString.append(varType.getPresentableText());
|
||||
ifStatementString.append(' ');
|
||||
@@ -306,44 +287,33 @@ public class ReplaceSwitchWithIfIntention extends Intention {
|
||||
}
|
||||
}
|
||||
for (PsiElement bodyStatement : bodyStatements) {
|
||||
@NonNls final String text = bodyStatement.getText();
|
||||
if (!"break;".equals(text)) {
|
||||
appendElement(bodyStatement, breakLabel, renameBreaks,
|
||||
ifStatementString);
|
||||
if (bodyStatement instanceof PsiBlockStatement) {
|
||||
final PsiBlockStatement blockStatement =
|
||||
(PsiBlockStatement) bodyStatement;
|
||||
final PsiCodeBlock codeBlock = blockStatement.getCodeBlock();
|
||||
final PsiStatement[] statements = codeBlock.getStatements();
|
||||
for (PsiStatement statement : statements) {
|
||||
appendElement(statement, ifStatementString);
|
||||
}
|
||||
} else {
|
||||
appendElement(bodyStatement, ifStatementString);
|
||||
}
|
||||
}
|
||||
ifStatementString.append("\n}");
|
||||
}
|
||||
|
||||
private static void appendElement(
|
||||
PsiElement element, String breakLabelString,
|
||||
boolean renameBreakElements,
|
||||
@NonNls StringBuilder ifStatementString) {
|
||||
if (!renameBreakElements) {
|
||||
final String text = element.getText();
|
||||
ifStatementString.append(text);
|
||||
} else if (element instanceof PsiBreakStatement) {
|
||||
PsiElement element, @NonNls StringBuilder ifStatementString) {
|
||||
if (element instanceof PsiBreakStatement) {
|
||||
final PsiBreakStatement breakStatement =
|
||||
(PsiBreakStatement) element;
|
||||
final PsiIdentifier identifier =
|
||||
((PsiBreakStatement)element).getLabelIdentifier();
|
||||
if (identifier == null || "".equals(identifier.getText())) {
|
||||
ifStatementString.append("break ");
|
||||
ifStatementString.append(breakLabelString);
|
||||
ifStatementString.append(';');
|
||||
} else {
|
||||
final String text = element.getText();
|
||||
ifStatementString.append(text);
|
||||
breakStatement.getLabelIdentifier();
|
||||
if (identifier == null) {
|
||||
return;
|
||||
}
|
||||
} else if (element instanceof PsiBlockStatement ||
|
||||
element instanceof PsiCodeBlock ||
|
||||
element instanceof PsiIfStatement) {
|
||||
final PsiElement[] children = element.getChildren();
|
||||
for (PsiElement child : children) {
|
||||
appendElement(child, breakLabelString, renameBreakElements,
|
||||
ifStatementString);
|
||||
}
|
||||
} else {
|
||||
final String text = element.getText();
|
||||
ifStatementString.append(text);
|
||||
}
|
||||
final String text = element.getText();
|
||||
ifStatementString.append(text);
|
||||
}
|
||||
}
|
||||
+49
-99
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2011 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.
|
||||
@@ -18,6 +18,7 @@ package com.siyeh.ipp.switchtoif;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.ipp.psiutils.EquivalenceChecker;
|
||||
import com.siyeh.ipp.psiutils.SideEffectChecker;
|
||||
@@ -26,69 +27,29 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class CaseUtil{
|
||||
class SwitchUtils {
|
||||
|
||||
private CaseUtil(){
|
||||
super();
|
||||
}
|
||||
private SwitchUtils(){}
|
||||
|
||||
private static boolean canBeCaseLabel(PsiExpression expression){
|
||||
private static boolean canBeCaseLabel(PsiExpression expression,
|
||||
LanguageLevel languageLevel){
|
||||
if(expression == null){
|
||||
return false;
|
||||
}
|
||||
if(expression instanceof PsiReferenceExpression){
|
||||
if (languageLevel.compareTo(LanguageLevel.JDK_1_5) >= 0
|
||||
&& expression instanceof PsiReferenceExpression){
|
||||
final PsiElement referent = ((PsiReference) expression).resolve();
|
||||
if(referent instanceof PsiEnumConstant){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final PsiType type = expression.getType();
|
||||
if(type == null){
|
||||
return false;
|
||||
}
|
||||
if(!type.equals(PsiType.INT) &&
|
||||
!type.equals(PsiType.CHAR) &&
|
||||
!type.equals(PsiType.LONG) &&
|
||||
!type.equals(PsiType.SHORT)){
|
||||
return false;
|
||||
}
|
||||
return PsiUtil.isConstantExpression(expression);
|
||||
}
|
||||
|
||||
public static boolean containsHiddenBreak(PsiStatement statement){
|
||||
return containsHiddenBreak(statement, true);
|
||||
}
|
||||
|
||||
private static boolean containsHiddenBreak(PsiStatement statement,
|
||||
boolean isTopLevel){
|
||||
if(statement instanceof PsiBlockStatement){
|
||||
final PsiCodeBlock codeBlock =
|
||||
((PsiBlockStatement) statement).getCodeBlock();
|
||||
final PsiStatement[] statements = codeBlock.getStatements();
|
||||
for(final PsiStatement childStatement : statements){
|
||||
if(containsHiddenBreak(childStatement, false)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof PsiIfStatement){
|
||||
final PsiIfStatement ifStatement = (PsiIfStatement) statement;
|
||||
final PsiStatement thenBranch = ifStatement.getThenBranch();
|
||||
final PsiStatement elseBranch = ifStatement.getElseBranch();
|
||||
return containsHiddenBreak(thenBranch, false) ||
|
||||
containsHiddenBreak(elseBranch, false);
|
||||
} else if(statement instanceof PsiBreakStatement){
|
||||
if(isTopLevel){
|
||||
return false;
|
||||
}
|
||||
final PsiIdentifier identifier =
|
||||
((PsiBreakStatement) statement).getLabelIdentifier();
|
||||
if(identifier == null){
|
||||
return true;
|
||||
}
|
||||
final String text = identifier.getText();
|
||||
return "".equals(text);
|
||||
}
|
||||
return false;
|
||||
return type != null &&
|
||||
(type.equals(PsiType.INT) ||
|
||||
type.equals(PsiType.CHAR) ||
|
||||
type.equals(PsiType.LONG) ||
|
||||
type.equals(PsiType.SHORT)) &&
|
||||
PsiUtil.isConstantExpression(expression);
|
||||
}
|
||||
|
||||
public static boolean isUsedByStatementList(PsiLocalVariable variable,
|
||||
@@ -109,17 +70,10 @@ class CaseUtil{
|
||||
return visitor.isUsed();
|
||||
}
|
||||
|
||||
public static String findUniqueLabel(PsiStatement statement,
|
||||
@NonNls String baseName){
|
||||
PsiElement ancestor = statement;
|
||||
while(ancestor.getParent() != null){
|
||||
if(ancestor instanceof PsiMethod
|
||||
|| ancestor instanceof PsiClass
|
||||
|| ancestor instanceof PsiFile){
|
||||
break;
|
||||
}
|
||||
ancestor = ancestor.getParent();
|
||||
}
|
||||
public static String findUniqueLabelName(PsiStatement statement,
|
||||
@NonNls String baseName){
|
||||
final PsiElement ancestor =
|
||||
PsiTreeUtil.getParentOfType(statement, PsiMember.class);
|
||||
if(!checkForLabel(baseName, ancestor)){
|
||||
return baseName;
|
||||
}
|
||||
@@ -140,37 +94,35 @@ class CaseUtil{
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiExpression getCaseExpression(PsiIfStatement statement){
|
||||
public static PsiExpression getSwitchExpression(PsiIfStatement statement){
|
||||
final PsiExpression condition = statement.getCondition();
|
||||
final LanguageLevel languageLevel =
|
||||
PsiUtil.getLanguageLevel(statement);
|
||||
final boolean stringSwitch =
|
||||
languageLevel.compareTo(LanguageLevel.JDK_1_7) >= 0;
|
||||
final PsiExpression possibleCaseExpression =
|
||||
determinePossibleCaseExpressions(condition, stringSwitch);
|
||||
if(possibleCaseExpression == null){
|
||||
final PsiExpression possibleSwitchExpression =
|
||||
determinePossibleSwitchExpressions(condition, languageLevel);
|
||||
if(possibleSwitchExpression == null){
|
||||
return null;
|
||||
}
|
||||
if (SideEffectChecker.mayHaveSideEffects(possibleCaseExpression)) {
|
||||
if (SideEffectChecker.mayHaveSideEffects(possibleSwitchExpression)) {
|
||||
return null;
|
||||
}
|
||||
while(true){
|
||||
final PsiExpression caseCondition = statement.getCondition();
|
||||
if (!canBeMadeIntoCase(caseCondition, possibleCaseExpression,
|
||||
stringSwitch)) {
|
||||
if (!canBeMadeIntoCase(caseCondition, possibleSwitchExpression,
|
||||
languageLevel)) {
|
||||
break;
|
||||
}
|
||||
final PsiStatement elseBranch = statement.getElseBranch();
|
||||
if(!(elseBranch instanceof PsiIfStatement)){
|
||||
return possibleCaseExpression;
|
||||
return possibleSwitchExpression;
|
||||
}
|
||||
statement = (PsiIfStatement) elseBranch;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiExpression determinePossibleCaseExpressions(
|
||||
PsiExpression expression, boolean stringSwitch){
|
||||
private static PsiExpression determinePossibleSwitchExpressions(
|
||||
PsiExpression expression, LanguageLevel languageLevel){
|
||||
while(expression instanceof PsiParenthesizedExpression){
|
||||
final PsiParenthesizedExpression parenthesizedExpression =
|
||||
(PsiParenthesizedExpression)expression;
|
||||
@@ -179,9 +131,9 @@ class CaseUtil{
|
||||
if (expression == null) {
|
||||
return null;
|
||||
}
|
||||
if (stringSwitch) {
|
||||
if (languageLevel.compareTo(LanguageLevel.JDK_1_7) >= 0) {
|
||||
final PsiExpression jdk17Expression =
|
||||
determinePossibleStringCaseExpression(expression);
|
||||
determinePossibleStringSwitchExpression(expression);
|
||||
if (jdk17Expression != null) {
|
||||
return jdk17Expression;
|
||||
}
|
||||
@@ -196,18 +148,18 @@ class CaseUtil{
|
||||
final PsiExpression lhs = binaryExpression.getLOperand();
|
||||
final PsiExpression rhs = binaryExpression.getROperand();
|
||||
if(operation.equals(JavaTokenType.OROR)){
|
||||
return determinePossibleCaseExpressions(lhs, stringSwitch);
|
||||
return determinePossibleSwitchExpressions(lhs, languageLevel);
|
||||
} else if(operation.equals(JavaTokenType.EQEQ)){
|
||||
if(canBeCaseLabel(lhs)){
|
||||
if(canBeCaseLabel(lhs, languageLevel)){
|
||||
return rhs;
|
||||
} else if (canBeCaseLabel(rhs)){
|
||||
} else if (canBeCaseLabel(rhs, languageLevel)){
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiExpression determinePossibleStringCaseExpression(
|
||||
private static PsiExpression determinePossibleStringSwitchExpression(
|
||||
PsiExpression expression) {
|
||||
if (!(expression instanceof PsiMethodCallExpression)) {
|
||||
return null;
|
||||
@@ -216,7 +168,8 @@ class CaseUtil{
|
||||
(PsiMethodCallExpression) expression;
|
||||
final PsiReferenceExpression methodExpression =
|
||||
methodCallExpression.getMethodExpression();
|
||||
final String referenceName = methodExpression.getReferenceName();
|
||||
@NonNls final String referenceName =
|
||||
methodExpression.getReferenceName();
|
||||
if (!"equals".equals(referenceName)) {
|
||||
return null;
|
||||
}
|
||||
@@ -251,15 +204,15 @@ class CaseUtil{
|
||||
|
||||
private static boolean canBeMadeIntoCase(
|
||||
PsiExpression expression, PsiExpression caseExpression,
|
||||
boolean stringSwitch) {
|
||||
LanguageLevel languageLevel) {
|
||||
while(expression instanceof PsiParenthesizedExpression){
|
||||
final PsiParenthesizedExpression parenthesizedExpression =
|
||||
(PsiParenthesizedExpression)expression;
|
||||
expression = parenthesizedExpression.getExpression();
|
||||
}
|
||||
if (stringSwitch) {
|
||||
if (languageLevel.compareTo(LanguageLevel.JDK_1_7) >=0 ) {
|
||||
final PsiExpression stringCaseExpression =
|
||||
determinePossibleStringCaseExpression(expression);
|
||||
determinePossibleStringSwitchExpression(expression);
|
||||
if (EquivalenceChecker.expressionsAreEquivalent(caseExpression,
|
||||
stringCaseExpression)) {
|
||||
return true;
|
||||
@@ -275,20 +228,17 @@ class CaseUtil{
|
||||
final PsiExpression lOperand = binaryExpression.getLOperand();
|
||||
final PsiExpression rhs = binaryExpression.getROperand();
|
||||
if(operation.equals(JavaTokenType.OROR)){
|
||||
return canBeMadeIntoCase(lOperand, caseExpression, stringSwitch) &&
|
||||
canBeMadeIntoCase(rhs, caseExpression, stringSwitch);
|
||||
return canBeMadeIntoCase(lOperand, caseExpression, languageLevel) &&
|
||||
canBeMadeIntoCase(rhs, caseExpression, languageLevel);
|
||||
} else if(operation.equals(JavaTokenType.EQEQ)){
|
||||
if(canBeCaseLabel(lOperand) &&
|
||||
EquivalenceChecker.expressionsAreEquivalent(caseExpression,
|
||||
rhs)){
|
||||
return true;
|
||||
} else if(canBeCaseLabel(rhs) &&
|
||||
EquivalenceChecker.expressionsAreEquivalent(caseExpression,
|
||||
lOperand)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else{
|
||||
return (canBeCaseLabel(lOperand, languageLevel) &&
|
||||
EquivalenceChecker.expressionsAreEquivalent(
|
||||
caseExpression, rhs))
|
||||
||
|
||||
(canBeCaseLabel(rhs, languageLevel) &&
|
||||
EquivalenceChecker.expressionsAreEquivalent(
|
||||
caseExpression, lOperand));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -528,14 +528,12 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
* the difference is that commit checkboxes should be checked only during the initial refresh - others should respect
|
||||
* user who could uncheck some commits.
|
||||
*/
|
||||
private void refreshTree(final boolean fetchData, final Map<VirtualFile, Set<String>> unchecked, final boolean updateTree) {
|
||||
private void refreshTree(final boolean fetchData, final Map<VirtualFile, Set<String>> unchecked, final boolean updateUncheckedCommits) {
|
||||
myCommitTree.setPaintBusy(true);
|
||||
loadRootsInBackground(fetchData, new PushActiveBranchRunnable(){
|
||||
@Override
|
||||
void run(List<Root> roots) {
|
||||
if (updateTree) {
|
||||
updateTree(roots, unchecked);
|
||||
}
|
||||
updateTree(roots, updateUncheckedCommits ? unchecked : null);
|
||||
updateUI();
|
||||
myCommitTree.setPaintBusy(false);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ classpath
|
||||
clazz
|
||||
clob
|
||||
closable
|
||||
closeable
|
||||
cmdline
|
||||
commandline
|
||||
config
|
||||
@@ -314,6 +315,7 @@ versa
|
||||
vertices
|
||||
webservice
|
||||
whitespace
|
||||
whitespaces
|
||||
wildcard
|
||||
workflow
|
||||
wsdl
|
||||
|
||||
@@ -224,6 +224,7 @@ nonterminated.comment=Unclosed comment
|
||||
assignment.to.itself=Variable is assigned to itself
|
||||
assignment.to.declared.variable=Variable ''{0}'' is initialized with self assignment
|
||||
exception.already.caught=Exception ''{0}'' has already been caught
|
||||
exception.double.caught.in.multi=Exception ''{0}'' is also caught by ''{1}''
|
||||
statement.must.be.prepended.with.case.label=Statement must be prepended with case label
|
||||
void.type.is.not.allowed='void' type is not allowed here
|
||||
single.import.class.conflict=''{0}'' is already defined in a single-type import
|
||||
@@ -310,6 +311,7 @@ unexpected.identifier=Unexpected identifier
|
||||
expected.gt='>' expected.
|
||||
expected.lbrace.or.semicolon='{' or ';' expected
|
||||
expected.parameter=Parameter expected
|
||||
expected.resource=Resource definition expected
|
||||
expected.type.parameter=Type parameter expected
|
||||
expected.comma=',' expected
|
||||
expected.comma.or.rparen=',' or ')' expected
|
||||
|
||||
Reference in New Issue
Block a user