diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index 6e9a6acb3429..ce7446774d6b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -584,7 +584,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } private void initOutputRootsFile(File rootsFile) throws IOException { - myOutputRootsStorage = new PersistentHashMap>>(rootsFile, new EnumeratorIntegerDescriptor(), new DataExternalizer>>() { + myOutputRootsStorage = new PersistentHashMap>>(rootsFile, EnumeratorIntegerDescriptor.INSTANCE, new DataExternalizer>>() { public void save(DataOutput out, TIntObjectHashMap> value) throws IOException { for (final TIntObjectIterator> it = value.iterator(); it.hasNext();) { it.advance(); diff --git a/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java b/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java index f5063ec125e7..fb7a5c6eb280 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java @@ -42,7 +42,7 @@ public class BackwardDependenciesStorage implements Flushable, Disposable { private static final int CLASS = 3; public BackwardDependenciesStorage(File file, final int cacheSize) throws IOException { - myMap = new PersistentHashMap(file, new EnumeratorIntegerDescriptor(), new MyDataExternalizer()); + myMap = new PersistentHashMap(file, EnumeratorIntegerDescriptor.INSTANCE, new MyDataExternalizer()); myCache = new SLRUCache(cacheSize * 2, cacheSize) { @NotNull diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index 69d02d778256..a838c6f3a4ef 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -182,7 +182,8 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration envs) { - this.myEnvs = envs; + myEnvs.clear(); + myEnvs.putAll(envs); } public boolean isPassParentEnvs() { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index f56bd1f662cb..12eeaf0a5a7e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -403,7 +403,7 @@ public class HighlightUtil { formatType(rType)); errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, assignment, message); - QuickFixAction.registerQuickFixAction(errorResult, new ChangeToAppendFix(eqOpSign, lType, rType, assignment)); + QuickFixAction.registerQuickFixAction(errorResult, new ChangeToAppendFix(eqOpSign, lType, assignment)); } return errorResult; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeToAppendFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeToAppendFix.java index bc52ba819893..d8bb0d29aab4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeToAppendFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeToAppendFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -23,8 +23,11 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Bas Leijdekkers @@ -33,13 +36,11 @@ public class ChangeToAppendFix implements IntentionAction { private final IElementType myTokenType; private final PsiType myLhsType; - private final PsiType myRhsType; private final PsiAssignmentExpression myAssignmentExpression; - public ChangeToAppendFix(IElementType eqOpSign, PsiType lType, PsiType rType, PsiAssignmentExpression assignmentExpression) { + public ChangeToAppendFix(IElementType eqOpSign, PsiType lType, PsiAssignmentExpression assignmentExpression) { myTokenType = eqOpSign; myLhsType = lType; - myRhsType = rType; myAssignmentExpression = assignmentExpression; } @@ -47,8 +48,9 @@ public class ChangeToAppendFix implements IntentionAction { @Override public String getText() { return QuickFixBundle.message("change.to.append.text", - myAssignmentExpression.getLExpression().getText(), - myAssignmentExpression.getRExpression().getText()); + buildAppendExpression(myAssignmentExpression.getRExpression(), + myLhsType.equalsToText("java.lang.Appendable"), + new StringBuilder(myAssignmentExpression.getLExpression().getText()))); } @NotNull @@ -61,9 +63,10 @@ public class ChangeToAppendFix implements IntentionAction { public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { return JavaTokenType.PLUSEQ == myTokenType && myAssignmentExpression.isValid() && - myAssignmentExpression.getManager().isInProject(myAssignmentExpression) && - myRhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING) && - (myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUILDER) || myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUFFER)); + PsiManager.getInstance(project).isInProject(myAssignmentExpression) && + (myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUILDER) || + myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUFFER) || + myLhsType.equalsToText("java.lang.Appendable")); } @Override @@ -74,14 +77,78 @@ public class ChangeToAppendFix implements IntentionAction { @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; - final PsiExpression rExpression = myAssignmentExpression.getRExpression(); - if (rExpression == null) { + final PsiExpression rhs = myAssignmentExpression.getRExpression(); + if (rhs == null) { + return; + } + final StringBuilder appendCallText = buildAppendExpression(rhs, myLhsType.equalsToText("java.lang.Appendable"), + new StringBuilder(myAssignmentExpression.getLExpression().getText())); + if (appendCallText == null) { return; } - final String appendCallText = - myAssignmentExpression.getLExpression().getText() + ".append(" + rExpression.getText() + ')'; final PsiElementFactory factory = JavaPsiFacade.getElementFactory(myAssignmentExpression.getProject()); - final PsiExpression appendCall = factory.createExpressionFromText(appendCallText, myAssignmentExpression); + final PsiExpression appendCall = factory.createExpressionFromText(appendCallText.toString(), myAssignmentExpression); myAssignmentExpression.replace(appendCall); } + + @Nullable + private static StringBuilder buildAppendExpression(PsiExpression concatenation, boolean useStringValueOf, @NonNls StringBuilder out) + throws IncorrectOperationException { + final PsiType type = concatenation.getType(); + if (type == null) { + return null; + } + if (concatenation instanceof PsiPolyadicExpression && type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)concatenation; + final PsiExpression[] operands = polyadicExpression.getOperands(); + boolean isConstant = true; + boolean isString = false; + final StringBuilder builder = new StringBuilder(); + for (PsiExpression operand : operands) { + if (isConstant && PsiUtil.isConstantExpression(operand)) { + if (builder.length() != 0) { + builder.append('+'); + } + final PsiType operandType = operand.getType(); + if (operandType != null && operandType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + isString = true; + } + builder.append(operand.getText()); + } + else { + isConstant = false; + if (builder.length() != 0) { + append(builder, useStringValueOf && !isString, out); + builder.setLength(0); + } + buildAppendExpression(operand, useStringValueOf, out); + } + } + if (builder.length() != 0) { + append(builder, false, out); + } + } + else if (concatenation instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)concatenation; + final PsiExpression expression = parenthesizedExpression.getExpression(); + if (expression != null) { + return buildAppendExpression(expression, useStringValueOf, out); + } + } + else { + append(concatenation.getText(), useStringValueOf && !type.equalsToText(CommonClassNames.JAVA_LANG_STRING), out); + } + return out; + } + + private static void append(CharSequence text, boolean useStringValueOf, StringBuilder out) { + out.append(".append("); + if (useStringValueOf) { + out.append("String.valueOf(").append(text).append(')'); + } + else { + out.append(text); + } + out.append(')'); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java index a8a5814a9dde..c87745948fec 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java @@ -234,7 +234,7 @@ public class PsiTypeLookupItem extends LookupItem { PsiFile file = context.getFile(); int newTail = JavaCompletionUtil.insertClassReference(aClass, file, context.getStartOffset(), context.getTailOffset()); context.setTailOffset(newTail); - PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(); JavaCompletionUtil.shortenReference(file, context.getStartOffset()); + PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index f980f68f8f2a..b6cff314da67 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -60,4 +60,6 @@ public interface DfaMemoryState { boolean isNotNull(DfaVariableValue dfaVar); void flushVariableOutOfScope(DfaVariableValue variable); + + void fieldReferenced(); } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index e291c92f2bcd..7763c26eaf1c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -51,7 +51,8 @@ public class DfaMemoryStateImpl implements DfaMemoryState { private Stack myStack; private TIntStack myOffsetStack; private TLongHashSet myDistinctClasses; - private Map myVariableStates; + private THashMap myVariableStates; + private boolean myHasDirtyFields = true; public DfaMemoryStateImpl(final DfaValueFactory factory) { myFactory = factory; @@ -80,6 +81,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { newState.myStateSize = myStateSize; newState.myVariableStates = new THashMap(); newState.myOffsetStack = new TIntStack(myOffsetStack); + newState.myHasDirtyFields = myHasDirtyFields; for (int i = 0; i < myEqClasses.size(); i++) { SortedIntSet aClass = myEqClasses.get(i); @@ -110,6 +112,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (!myStack.equals(that.myStack)) return false; if (!myOffsetStack.equals(that.myOffsetStack)) return false; if (!myVariableStates.equals(that.myVariableStates)) return false; + if (myHasDirtyFields != that.myHasDirtyFields) return false; int[] permutation = getPermutationToSortedState(); int[] thatPermutation = that.getPermutationToSortedState(); @@ -461,6 +464,11 @@ public class DfaMemoryStateImpl implements DfaMemoryState { myDistinctClasses.add(createPair(c1Index, c2Index)); } + @Override + public void fieldReferenced() { + myHasDirtyFields = true; + } + public boolean isNull(DfaValue dfaValue) { if (dfaValue instanceof DfaNotNullValue) return false; @@ -674,6 +682,9 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } public void flushFields(DataFlowRunner runner) { + if (!myHasDirtyFields) return; + + myHasDirtyFields = false; DfaVariableValue[] fields = runner.getFields(); for (DfaVariableValue field : fields) { boolean resetNullability = isNotNull(field); @@ -690,17 +701,19 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } doFlash(variable); - doFlash((DfaVariableValue)variable.createNegated()); } @Override public void flushVariableOutOfScope(DfaVariableValue variable) { doFlash(variable); - doFlash((DfaVariableValue)variable.createNegated()); } - private void doFlash(DfaVariableValue variable) { - final int id = variable.getID(); + private void doFlash(DfaVariableValue varPlain) { + DfaVariableValue varNegated = (DfaVariableValue)varPlain.createNegated(); + + final int idPlain = varPlain.getID(); + final int idNegated = varNegated.getID(); + int size = myEqClasses.size(); int interruptCount = 0; for (int varClassIndex = 0; varClassIndex < size; varClassIndex++) { @@ -713,9 +726,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } int cl = varClass.get(i); DfaValue value = myFactory.getValue(cl); - if (value != null && id == value.getID() || - value instanceof DfaBoxedValue && ((DfaBoxedValue)value).getWrappedValue().getID() == id || - value instanceof DfaUnboxedValue && ((DfaUnboxedValue)value).getVariable().getID() == id) { + if (mine(idPlain, value) || mine(idNegated, value)) { varClass.remove(i); break; } @@ -733,6 +744,13 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } } - myVariableStates.remove(variable); + myVariableStates.remove(varPlain); + myVariableStates.remove(varNegated); + } + + private static boolean mine(int id, DfaValue value) { + return value != null && id == value.getID() || + value instanceof DfaBoxedValue && ((DfaBoxedValue)value).getWrappedValue().getID() == id || + value instanceof DfaUnboxedValue && ((DfaUnboxedValue)value).getVariable().getID() == id; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 218c68c27659..5ce2fbd6c1f5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -119,6 +119,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { @Override public DfaInstructionState[] visitFieldReference(FieldReferenceInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { + memState.fieldReferenced(); final DfaValue qualifier = memState.pop(); if (instruction.getExpression().isPhysical() && !memState.applyNotNull(qualifier)) { onInstructionProducesNPE(instruction, runner); diff --git a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java b/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java index 629a3d6ccea7..95d78fafed51 100644 --- a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java +++ b/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java @@ -86,4 +86,5 @@ public interface CommonClassNames { @NonNls String JAVA_LANG_INVOKE_MH_POLYMORPHIC = "java.lang.invoke.MethodHandle.PolymorphicSignature"; String TARGET_ANNOTATION_FQ_NAME = "java.lang.annotation.Target"; + @NonNls String JAVA_LANG_RUNNABLE = "java.lang.Runnable"; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java index 305349986c5c..33de2b108a08 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java @@ -86,7 +86,7 @@ public class ElementPresentationUtil implements PlatformIcons { private static final int FLAGS_STATIC = 0x200; private static final int FLAGS_FINAL = 0x400; private static final int FLAGS_JUNIT_TEST = 0x2000; - private static final int FLAGS_RUNNABLE = 0x4000; + public static final int FLAGS_RUNNABLE = 0x4000; private static final Key> CLASS_KIND_KEY = new Key>("CLASS_KIND_KEY"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/after1.java new file mode 100644 index 000000000000..86f4d45fe9d2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/after1.java @@ -0,0 +1,6 @@ +// "Change to 'appendable.append(1)'" "true" +class Test { + void appendable(StringBuilder appendable) throws IOException { + appendable.append(1); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/after2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/after2.java new file mode 100644 index 000000000000..47e5b2b3f230 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/after2.java @@ -0,0 +1,7 @@ +// "Change to 'builder.append(1+1).append(s).append(" ")'" "true" +class Test { + String s; + void bar(StringBuilder builder) { + builder.append(1 + 1).append(s).append(" "); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/before1.java new file mode 100644 index 000000000000..a10a2bf7ae44 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/before1.java @@ -0,0 +1,6 @@ +// "Change to 'appendable.append(1)'" "true" +class Test { + void appendable(StringBuilder appendable) throws IOException { + appendable += 1; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/before2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/before2.java new file mode 100644 index 000000000000..0932be483d67 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend/before2.java @@ -0,0 +1,7 @@ +// "Change to 'builder.append(1+1).append(s).append(" ")'" "true" +class Test { + String s; + void bar(StringBuilder builder) { + builder += 1 + 1 + s + " "; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ChangeToAppendTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ChangeToAppendTest.java new file mode 100644 index 000000000000..c7d1a7b7a237 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ChangeToAppendTest.java @@ -0,0 +1,11 @@ +package com.intellij.codeInsight.daemon.quickFix; + +public class ChangeToAppendTest extends LightQuickFixTestCase { + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/changeToAppend"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/psi/SrcRepositoryUseTest.java b/java/java-tests/testSrc/com/intellij/psi/SrcRepositoryUseTest.java index 3adb210eff3e..b91d6f4213a5 100644 --- a/java/java-tests/testSrc/com/intellij/psi/SrcRepositoryUseTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/SrcRepositoryUseTest.java @@ -174,8 +174,8 @@ public class SrcRepositoryUseTest extends PsiTestCase{ PsiClass aClass = classes[0]; PsiClass[] superTypes = aClass.getSupers(); LOG.assertTrue(superTypes.length == 2); - LOG.assertTrue(superTypes[0].getQualifiedName().equals("java.lang.String")); - LOG.assertTrue(superTypes[1].getQualifiedName().equals("java.lang.Runnable")); + LOG.assertTrue(superTypes[0].getQualifiedName().equals(CommonClassNames.JAVA_LANG_STRING)); + LOG.assertTrue(superTypes[1].getQualifiedName().equals(CommonClassNames.JAVA_LANG_RUNNABLE)); teardownLoadingFilter(); } diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ExtendsBoundListTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ExtendsBoundListTest.java index 76559f6b058a..ec7481a19a35 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ExtendsBoundListTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ExtendsBoundListTest.java @@ -79,7 +79,7 @@ public class ExtendsBoundListTest extends LightCodeInsightTestCase { final PsiTypeParameter typeParameter = getTypeParameter(); final PsiReferenceList extendsList = typeParameter.getExtendsList(); final JavaPsiFacade manager = getJavaFacade(); - final PsiClass clonableClass = manager.findClass("java.lang.Runnable"); + final PsiClass clonableClass = manager.findClass(CommonClassNames.JAVA_LANG_RUNNABLE); assertNotNull(clonableClass); final PsiJavaCodeReferenceElement reference = manager.getElementFactory().createClassReferenceElement(clonableClass); extendsList.add(reference); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java index 3189e82f2ea7..77d7fcdea41e 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java @@ -208,7 +208,7 @@ public class ChangeSignatureTest extends LightRefactoringTestCase { } public void testCovariantReturnType() throws Exception { - doTest("java.lang.Runnable", new ParameterInfoImpl[0], false); + doTest(CommonClassNames.JAVA_LANG_RUNNABLE, new ParameterInfoImpl[0], false); } public void testReorderExceptions() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java index aad754cc357f..4c3375a717ca 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java @@ -3,6 +3,7 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiType; @@ -53,7 +54,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { } public void testAnonymousClass1() throws Exception { - doTest(new MockIntroduceVariableHandler("runnable", false, false, false, "java.lang.Runnable")); + doTest(new MockIntroduceVariableHandler("runnable", false, false, false, CommonClassNames.JAVA_LANG_RUNNABLE)); } public void testAnonymousClass2() throws Exception { diff --git a/platform/lang-api/src/com/intellij/execution/configuration/AbstractRunConfiguration.java b/platform/lang-api/src/com/intellij/execution/configuration/AbstractRunConfiguration.java index 0a21fc63d03e..f5c0747209fc 100644 --- a/platform/lang-api/src/com/intellij/execution/configuration/AbstractRunConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configuration/AbstractRunConfiguration.java @@ -23,7 +23,8 @@ public abstract class AbstractRunConfiguration extends ModuleBasedConfiguration< } public void setEnvs(final Map envs) { - myEnvs = envs; + myEnvs.clear(); + myEnvs.putAll(envs); } public boolean isPassParentEnvs() { diff --git a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java index 9de175f3f8b3..e7c4120a4109 100644 --- a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java +++ b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java @@ -72,7 +72,8 @@ public class EnvironmentVariablesComponent extends LabeledComponent envs) { - myEnvs = envs; + myEnvs.clear(); + myEnvs.putAll(envs); @NonNls final StringBuilder buf = StringBuilderSpinAllocator.alloc(); try { for (String variable : myEnvs.keySet()) { diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingProvider.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingProvider.java index 4086abd7de9a..19ee659299f1 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingProvider.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingProvider.java @@ -35,6 +35,14 @@ public abstract class CustomFoldingProvider { public abstract boolean isCustomRegionStart(String elementText); public abstract boolean isCustomRegionEnd(String elementText); public abstract String getPlaceholderText(String elementText); + + /** + * @return A description string shown in "Surround With" action. + */ + public abstract String getDescription(); + + public abstract String getStartString(); + public abstract String getEndString(); public boolean isCollapsedByDefault(String text) { return false; diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java new file mode 100644 index 000000000000..3f3a4ed0a570 --- /dev/null +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java @@ -0,0 +1,183 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.folding; + +import com.intellij.lang.Commenter; +import com.intellij.lang.Language; +import com.intellij.lang.LanguageCommenters; +import com.intellij.lang.surroundWith.SurroundDescriptor; +import com.intellij.lang.surroundWith.Surrounder; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Rustam Vishnyakov + */ +public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { + + public final static CustomFoldingSurroundDescriptor INSTANCE = new CustomFoldingSurroundDescriptor(); + public final static CustomFoldingRegionSurrounder[] SURROUNDERS; + + private final static String DEFAULT_DESC_TEXT = "Description"; + + static { + List surrounderList = new ArrayList(); + for (CustomFoldingProvider provider : CustomFoldingProvider.getAllProviders()) { + surrounderList.add(new CustomFoldingRegionSurrounder(provider)); + } + SURROUNDERS = surrounderList.toArray(new CustomFoldingRegionSurrounder[surrounderList.size()]); + } + + @NotNull + @Override + public PsiElement[] getElementsToSurround(PsiFile file, int startOffset, int endOffset) { + if (startOffset >= endOffset - 1) return PsiElement.EMPTY_ARRAY; + Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(file.getLanguage()); + if (commenter == null || commenter.getLineCommentPrefix() == null) return PsiElement.EMPTY_ARRAY; + PsiElement startElement = file.findElementAt(startOffset); + if (startElement instanceof PsiWhiteSpace) startElement = startElement.getNextSibling(); + PsiElement endElement = file.findElementAt(endOffset - 1); + if (endElement instanceof PsiWhiteSpace) endElement = endElement.getPrevSibling(); + if (startElement != null && endElement != null) { + if (startElement.getTextRange().getStartOffset() > endElement.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY; + startElement = findClosestParentAfterLineBreak(startElement); + if (startElement != null) { + endElement = findClosestParentBeforeLineBreak(endElement); + if (endElement != null) { + PsiElement commonParent = startElement.getParent(); + if (endElement.getParent() == commonParent) { + if (startElement == endElement) return new PsiElement[] {startElement}; + return new PsiElement[] {startElement, endElement}; + } + } + } + } + return PsiElement.EMPTY_ARRAY; + } + + @Nullable + private static PsiElement findClosestParentAfterLineBreak(PsiElement element) { + PsiElement parent = element; + while (parent != null) { + PsiElement prev = parent.getPrevSibling(); + if (prev instanceof PsiWhiteSpace && prev.textContains('\n')) return parent; + parent = parent.getParent(); + } + return null; + } + + @Nullable + private static PsiElement findClosestParentBeforeLineBreak(PsiElement element) { + PsiElement parent = element; + while (parent != null) { + PsiElement next = parent.getNextSibling(); + if (next instanceof PsiWhiteSpace && next.textContains('\n')) return parent; + parent = parent.getParent(); + } + return null; + } + + @NotNull + @Override + public Surrounder[] getSurrounders() { + return SURROUNDERS; + } + + @Override + public boolean isExclusive() { + return false; + } + + private static class CustomFoldingRegionSurrounder implements Surrounder { + + private CustomFoldingProvider myProvider; + + public CustomFoldingRegionSurrounder(@NotNull CustomFoldingProvider provider) { + myProvider = provider; + } + + @Override + public String getTemplateDescription() { + return myProvider.getDescription(); + } + + @Override + public boolean isApplicable(@NotNull PsiElement[] elements) { + return true; + } + + @Override + public TextRange surroundElements(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement[] elements) + throws IncorrectOperationException { + if (elements.length == 0) return null; + PsiElement firstElement = elements[0]; + PsiElement lastElement = elements[elements.length - 1]; + PsiFile psiFile = firstElement.getContainingFile(); + Language language = psiFile.getLanguage(); + Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(language); + if (commenter == null) return null; + String linePrefix = commenter.getLineCommentPrefix(); + if (linePrefix == null) return null; + int prefixLength = linePrefix.length(); + int startOffset = firstElement.getTextRange().getStartOffset(); + int endOffset = lastElement.getTextRange().getEndOffset(); + int delta = 0; + TextRange rangeToSelect = new TextRange(startOffset, startOffset); + String startText = myProvider.getStartString(); + int descPos = startText.indexOf("?"); + if (descPos >= 0) { + startText = startText.replace("?", DEFAULT_DESC_TEXT); + rangeToSelect = new TextRange(startOffset + descPos, startOffset + descPos + DEFAULT_DESC_TEXT.length()); + } + String startString = linePrefix + startText + "\n"; + String endString = "\n" + linePrefix + myProvider.getEndString(); + editor.getDocument().insertString(endOffset, endString); + delta += endString.length(); + editor.getDocument().insertString(startOffset, startString); + delta += startString.length(); + rangeToSelect = rangeToSelect.shiftRight(prefixLength); + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + documentManager.commitDocument(documentManager.getDocument(psiFile)); + adjustLineIndent(project, psiFile, language, + new TextRange(endOffset + delta - endString.length(), endOffset + delta)); + adjustLineIndent(project, psiFile, language, + new TextRange(startOffset, startOffset + startString.length())); + return rangeToSelect; + } + + private static void adjustLineIndent(@NotNull Project project, PsiFile file, Language language, TextRange range) { + CommonCodeStyleSettings formatSettings = CodeStyleSettingsManager.getSettings(project).getCommonSettings(language); + boolean keepAtFirstCol = formatSettings.KEEP_FIRST_COLUMN_COMMENT; + formatSettings.KEEP_FIRST_COLUMN_COMMENT = false; + CodeStyleManager.getInstance(project).adjustLineIndent(file, range); + formatSettings.KEEP_FIRST_COLUMN_COMMENT = keepAtFirstCol; + } + } +} diff --git a/platform/lang-api/src/com/intellij/psi/stubs/IntStubIndexExtension.java b/platform/lang-api/src/com/intellij/psi/stubs/IntStubIndexExtension.java index 098296e0fcc4..e0b076115cd4 100644 --- a/platform/lang-api/src/com/intellij/psi/stubs/IntStubIndexExtension.java +++ b/platform/lang-api/src/com/intellij/psi/stubs/IntStubIndexExtension.java @@ -29,6 +29,6 @@ public abstract class IntStubIndexExtension extends Abst } public KeyDescriptor getKeyDescriptor() { - return new EnumeratorIntegerDescriptor(); + return EnumeratorIntegerDescriptor.INSTANCE; } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index 2b81d90aa761..f19a2408fdda 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -33,8 +33,10 @@ import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.Language; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; @@ -442,7 +444,14 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } void disposeIndicator() { - Disposer.dispose(this); + // our offset map should be disposed under write action, so that duringCompletion (read action) won't access it after disposing + AccessToken token = WriteAction.start(); + try { + Disposer.dispose(this); + } + finally { + token.finish(); + } } @TestOnly diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java index 15404e5792a3..52bc48359f2e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java @@ -29,6 +29,7 @@ import com.intellij.codeInsight.template.impl.WrapWithCustomTemplateAction; import com.intellij.ide.DataManager; import com.intellij.lang.Language; import com.intellij.lang.LanguageSurrounders; +import com.intellij.lang.folding.CustomFoldingSurroundDescriptor; import com.intellij.lang.surroundWith.SurroundDescriptor; import com.intellij.lang.surroundWith.Surrounder; import com.intellij.openapi.actionSystem.*; @@ -107,6 +108,7 @@ public class SurroundWithHandler implements CodeInsightActionHandler { surroundDescriptors.addAll(LanguageSurrounders.INSTANCE.allForLanguage(l)); if (l != baseLanguage) surroundDescriptors.addAll(LanguageSurrounders.INSTANCE.allForLanguage(baseLanguage)); + surroundDescriptors.add(CustomFoldingSurroundDescriptor.INSTANCE); int exclusiveCount = 0; List exclusiveSurroundDescriptors = new ArrayList(); @@ -152,8 +154,12 @@ public class SurroundWithHandler implements CodeInsightActionHandler { for (SurroundDescriptor descriptor : surroundDescriptors) { final PsiElement[] elements = descriptor.getElementsToSurround(file, startOffset, endOffset); if (elements.length > 0) { - doSurround(project, editor, surrounder, elements); - return; + for (Surrounder descriptorSurrounder : descriptor.getSurrounders()) { + if (surrounder.getClass().equals(descriptorSurrounder.getClass())) { + doSurround(project, editor, surrounder, elements); + return; + } + } } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index e4a9a301b0c9..d8574ce19d64 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -784,7 +784,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable int bs = myEditor.logicalPositionToOffset(new LogicalPosition(line, blockStart.column)); int start = bs - prefix.length(); int end = myEditor.logicalPositionToOffset(new LogicalPosition(line, blockEnd.column)); - if (start >= end) { + if (start > end) { LOG.error("bs=" + bs + "; start=" + start + "; end=" + end + "; blockStart=" + blockStart + "; blockEnd=" + blockEnd + "; line=" + line + "; len=" + (document.getLineEndOffset(line) - document.getLineStartOffset(line))); @@ -1275,7 +1275,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable public void hideLookup(boolean explicitly) { ApplicationManager.getApplication().assertIsDispatchThread(); - if (myDisposed) return; + if (myHidden) return; doHide(true, explicitly); } diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index 4f94c701fcd8..2e879b03b8ad 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -763,7 +763,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data myLivePreviewController.setReplaceListener(this); mySearchResults.addListener(this); - myLivePreviewController.updateInBackground(myFindModel, false); + updateResults(false); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java index ba6a97d45fc0..034701937e3c 100644 --- a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java +++ b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java @@ -76,7 +76,7 @@ public class TrigramIndex extends ScalarIndexExtension { @Override public KeyDescriptor getKeyDescriptor() { - return new EnumeratorIntegerDescriptor(); + return EnumeratorIntegerDescriptor.INSTANCE; } @Override diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/NetBeansCustomFoldingProvider.java b/platform/lang-impl/src/com/intellij/lang/customFolding/NetBeansCustomFoldingProvider.java index feef6f0c8d07..4ce8a5aff6f4 100644 --- a/platform/lang-impl/src/com/intellij/lang/customFolding/NetBeansCustomFoldingProvider.java +++ b/platform/lang-impl/src/com/intellij/lang/customFolding/NetBeansCustomFoldingProvider.java @@ -38,6 +38,21 @@ public class NetBeansCustomFoldingProvider extends CustomFoldingProvider { return customText.isEmpty() ? "..." : customText; } + @Override + public String getDescription() { + return " Comments"; + } + + @Override + public String getStartString() { + return ""; + } + + @Override + public String getEndString() { + return ""; + } + @Override public boolean isCollapsedByDefault(String text) { return text.matches(".*defaultstate\\s*=\\s*\"collapsed\".*"); diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/VisualStudioCustomFoldingProvider.java b/platform/lang-impl/src/com/intellij/lang/customFolding/VisualStudioCustomFoldingProvider.java index 784e9a64ccab..8aea576691a7 100644 --- a/platform/lang-impl/src/com/intellij/lang/customFolding/VisualStudioCustomFoldingProvider.java +++ b/platform/lang-impl/src/com/intellij/lang/customFolding/VisualStudioCustomFoldingProvider.java @@ -37,4 +37,18 @@ public class VisualStudioCustomFoldingProvider extends CustomFoldingProvider { return elementText.replaceFirst("..?\\s*region(.*)","$1").trim(); } + @Override + public String getDescription() { + return "region...endregion Comments"; + } + + @Override + public String getStartString() { + return "region ?"; + } + + @Override + public String getEndString() { + return "endregion"; + } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java index 9d38a9e0607f..5c2c48ed64fc 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java @@ -108,6 +108,11 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer return getMergedData().isAssociated(value, inputId); } + @Override + public IntPredicate getValueAssociationPredicate(Value value) { + return getMergedData().getValueAssociationPredicate(value); + } + @Override public IntIterator getInputIdsIterator(final Value value) { return getMergedData().getInputIdsIterator(value); @@ -119,7 +124,7 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer // need 'synchronized' to ensure atomic initialization of merged data // because several threads that acquired read lock may simultaneously execute the method - private ValueContainer getMergedData() { + private ValueContainerImpl getMergedData() { ValueContainerImpl merged = myMerged; if (merged != null) { return merged; @@ -129,16 +134,15 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer if (merged != null) { return merged; } - final ValueContainerImpl newMerged = new ValueContainerImpl(); final ValueContainer fromDisk = myInitializer.compute(); + final ValueContainerImpl newMerged; - fromDisk.forEach(new ContainerAction() { - @Override - public void perform(final int id, final Value value) { - newMerged.addValue(id, value); - } - }); + if (fromDisk instanceof ValueContainerImpl) { + newMerged = ((ValueContainerImpl)fromDisk).clone(); + } else { + newMerged = ((ChangeTrackingValueContainer)fromDisk).getMergedData().clone(); + } myInvalidated.forEach(new TIntProcedure() { @Override public boolean execute(int inputId) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 5594a35166ae..0eb0089fd3c1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -63,8 +63,6 @@ import com.intellij.util.*; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ConcurrentHashSet; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashMap; -import com.intellij.util.containers.HashSet; import com.intellij.util.io.*; import com.intellij.util.io.DataOutputStream; import com.intellij.util.io.storage.HeavyProcessLatch; @@ -171,7 +169,7 @@ public class FileBasedIndex implements ApplicationComponent { @Override public void beforeFileTypesChanged(final FileTypeEvent event) { cleanupProcessedFlag(); - myTypeToExtensionMap = new HashMap>(); + myTypeToExtensionMap = new THashMap>(); for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { myTypeToExtensionMap.put(type, getExtensions(type)); } @@ -182,7 +180,7 @@ public class FileBasedIndex implements ApplicationComponent { final Map> oldExtensions = myTypeToExtensionMap; myTypeToExtensionMap = null; if (oldExtensions != null) { - final Map> newExtensions = new HashMap>(); + final Map> newExtensions = new THashMap>(); for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { newExtensions.put(type, getExtensions(type)); } @@ -204,7 +202,7 @@ public class FileBasedIndex implements ApplicationComponent { } private Set getExtensions(FileType type) { - final Set set = new HashSet(); + final Set set = new THashSet(); for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { set.add(matcher.getPresentableString()); } @@ -434,7 +432,7 @@ public class FileBasedIndex implements ApplicationComponent { } private static Set readRegisteredIndexNames() { - final Set result = new HashSet(); + final Set result = new THashSet(); try { final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); try { @@ -493,7 +491,7 @@ public class FileBasedIndex implements ApplicationComponent { MemoryIndexStorage storage) throws IOException { final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); final Ref isBufferingMode = new Ref(false); - final Map> tempMap = new HashMap>(); + final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); final DataExternalizer> dataExternalizer = new DataExternalizer>() { @Override @@ -532,7 +530,7 @@ public class FileBasedIndex implements ApplicationComponent { // cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects. final PersistentHashMap> map = new PersistentHashMap>( - indexStorageFile, new EnumeratorIntegerDescriptor(), dataExternalizer + indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, dataExternalizer ) { @Override @@ -667,7 +665,7 @@ public class FileBasedIndex implements ApplicationComponent { */ @NotNull public Collection getAllKeys(final ID indexId, @NotNull Project project) { - Set allKeys = new HashSet(); + Set allKeys = new THashSet(); processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); return allKeys; } @@ -829,7 +827,7 @@ public class FileBasedIndex implements ApplicationComponent { @NotNull public Collection getContainingFiles(final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final Set files = new HashSet(); + final Set files = new THashSet(); processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { @Override public boolean process(final VirtualFile file, final V value) { @@ -1021,7 +1019,7 @@ public class FileBasedIndex implements ApplicationComponent { for (K dataKey : dataKeys) { ProgressManager.checkCanceled(); - TIntHashSet copy = new TIntHashSet(); + final TIntHashSet copy = new TIntHashSet(); final ValueContainer container = index.getData(dataKey); for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { @@ -1029,12 +1027,27 @@ public class FileBasedIndex implements ApplicationComponent { if (valueChecker != null && !valueChecker.value(value)) { continue; } - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext(); ) { - final int id = inputIdsIterator.next(); - if ((mainIntersection == null || mainIntersection.contains(id)) && - (projectFilesFilter == null || projectFilesFilter.contains(id))) { - copy.add(id); + + ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); + + if (mainIntersection == null || iterator.size() < mainIntersection.size()) { + for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { + final int id = inputIdsIterator.next(); + if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || + mainIntersection != null && mainIntersection.contains(id) + ) { + copy.add(id); + } } + } else { + mainIntersection.forEach(new TIntProcedure() { + final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); + @Override + public boolean execute(int id) { + if (predicate.contains(id)) copy.add(id); + return true; + } + }); } } @@ -1249,7 +1262,7 @@ public class FileBasedIndex implements ApplicationComponent { } private Set getUnsavedOrTransactedDocuments() { - final Set docs = new HashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); + final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); synchronized (myTransactionMap) { docs.addAll(myTransactionMap.keySet()); } @@ -2161,7 +2174,7 @@ public class FileBasedIndex implements ApplicationComponent { return; } - Set visitedRoots = new HashSet(); + Set visitedRoots = new THashSet(); for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { //important not to depend on project here, to support per-project background reindex // each client gives a project to FileBasedIndex diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java index bdfdc4b4e0bb..dfba581b400e 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java @@ -31,11 +31,17 @@ public abstract class ValueContainer { int size(); } + + static abstract class IntPredicate { + abstract boolean contains(int id); + } public abstract IntIterator getInputIdsIterator(Value value); public abstract boolean isAssociated(Value value, int inputId); - + + public abstract IntPredicate getValueAssociationPredicate(Value value); + public abstract Iterator getValueIterator(); public abstract List toValueList(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index 9a15c3fc8b12..249a2b096d3d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java @@ -17,9 +17,11 @@ package com.intellij.util.indexing; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.containers.EmptyIterator; import gnu.trove.THashMap; import gnu.trove.TIntHashSet; import gnu.trove.TIntIterator; +import gnu.trove.TObjectObjectProcedure; import java.util.*; @@ -29,7 +31,6 @@ import java.util.*; */ class ValueContainerImpl extends UpdatableValueContainer implements Cloneable{ private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.ValueContainerImpl"); - private THashMap myInputIdMapping; public ValueContainerImpl() { @@ -117,6 +118,10 @@ class ValueContainerImpl extends UpdatableValueContainer implement @Override public Iterator getValueIterator() { + if (myInputIdMapping.size() == 0) { + return EmptyIterator.getInstance(); + } + final Set values = Collections.unmodifiableSet(myInputIdMapping.keySet()); return new Iterator() { final Iterator iterator = values.iterator(); @@ -161,6 +166,28 @@ class ValueContainerImpl extends UpdatableValueContainer implement return false; } + @Override + public IntPredicate getValueAssociationPredicate(Value value) { + final Object input = myInputIdMapping.get(value); + if (input == null) return EMPTY_PREDICATE; + if (input instanceof Integer) { + return new IntPredicate() { + final int myId = (Integer)input; + @Override + public boolean contains(int id) { + return id == myId; + } + }; + } + return new IntPredicate() { + final TIntHashSet mySet = (TIntHashSet)input; + @Override + boolean contains(int id) { + return mySet.contains(id); + } + }; + } + @Override public IntIterator getInputIdsIterator(Value value) { value = maskNull(value); @@ -266,15 +293,26 @@ class ValueContainerImpl extends UpdatableValueContainer implement return null; } final THashMap cloned = map.clone(); - for (Value key : cloned.keySet()) { - final Object val = cloned.get(key); - if (val instanceof TIntHashSet) { - cloned.put(key, ((TIntHashSet)val).clone()); + cloned.forEachEntry(new TObjectObjectProcedure() { + @Override + public boolean execute(Value key, Object val) { + if (val instanceof TIntHashSet) { + cloned.put(key, ((TIntHashSet)val).clone()); + } + return true; } - } + }); + return cloned; } + private static final IntPredicate EMPTY_PREDICATE = new IntPredicate() { + @Override + public boolean contains(int id) { + return false; + } + }; + private static class IdSet extends TIntHashSet { private IdSet(final int initialCapacity, final float loadFactor) { diff --git a/platform/platform-api/src/com/intellij/ui/table/TableView.java b/platform/platform-api/src/com/intellij/ui/table/TableView.java index b62334b42962..9d79f0a9e96a 100644 --- a/platform/platform-api/src/com/intellij/ui/table/TableView.java +++ b/platform/platform-api/src/com/intellij/ui/table/TableView.java @@ -41,6 +41,15 @@ public class TableView extends BaseTableView implements ItemsProvider, Sel super.setModel(dataModel); } + /** + * use {@link #setModelAndUpdateColumns(com.intellij.util.ui.ListTableModel)} instead + * @param model + */ + @Deprecated + public void setModel(final ListTableModel model) { + setModelAndUpdateColumns(model); + } + public void setModelAndUpdateColumns(final ListTableModel model) { super.setModel(model); updateColumnSizes(); diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java index 72f32c0bfe90..cb7c1f760e2c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java @@ -711,7 +711,27 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra addWindowListener(macFullScreenPatchListener); } + if (SystemInfo.isMac && Registry.is("ide.mac.fix.dialog.showing")) { + final Window owner = getOwner(); + if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow() != owner) { + final Ref dialogFixerRef = new Ref(); + final WindowAdapter dialogFixer = new WindowAdapter() { + @Override + public void windowActivated(WindowEvent e) { + owner.removeWindowListener(dialogFixerRef.get()); + superShow(); + } + }; + dialogFixerRef.set(dialogFixer); + owner.addWindowListener(dialogFixer); + return; + } + } + superShow(); + } + + private void superShow() { super.show(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java index 6e59820b2a3a..96ddf7871abe 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java @@ -379,6 +379,8 @@ public class ToolWindowContentUi extends JPanel implements ContentUI, PropertyCh hideWindow(e); } } + } else { + hideWindow(e); } } else { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java index 53f1f9e0ff04..41bf86dacad0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java @@ -18,6 +18,7 @@ package com.intellij.openapi.wm.impl.status; import com.intellij.notification.EventLog; import com.intellij.notification.Notification; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.Pair; @@ -39,6 +40,7 @@ import java.awt.event.MouseEvent; * @author peter */ class StatusPanel extends JPanel { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.status.StatusPanel"); private boolean myLogMode; private int myTimeStart; private boolean myDirty; @@ -58,6 +60,9 @@ class StatusPanel extends JPanel { @Override protected String truncateText(String text, Rectangle bounds, FontMetrics fm, Rectangle textR, Rectangle iconR, int maxWidth) { if (myTimeStart > 0) { + if (myTimeStart >= text.length()) { + LOG.error(myTimeStart + " " + text.length()); + } final String time = text.substring(myTimeStart); final int withoutTime = maxWidth - fm.stringWidth(time); @@ -165,6 +170,8 @@ class StatusPanel extends JPanel { if (myDirty || System.currentTimeMillis() - statusMessage.second >= DateFormatUtil.MINUTE) { myTimeStart = text.length() + 1; text += " (" + StringUtil.decapitalize(DateFormatUtil.formatPrettyDateTime(statusMessage.second)) + ")"; + } else { + myTimeStart = -1; } setStatusText(text); alarm.addRequest(this, 30000); diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 25819ceda9e5..7a709b1179ae 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -108,6 +108,7 @@ ide.mac.filechooser.showhidden.files=false ide.mac.filechooser.native=true ide.mac.message.dialogs.as.sheets=true ide.mac.inplaceDialogMnemonicsFix=true +ide.mac.fix.dialog.showing=false ide.mac.hide.cursor.when.typing=false ide.mac.show.native.help=false ide.mac.useNativeClipboard=false diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 71e71761ba30..cd07c42dfc12 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1308,8 +1308,8 @@ string.buffer.replaceable.by.string.builder.replace.quickfix=Replace with 'Strin string.buffer.to.string.in.concatenation.remove.quickfix=Remove 'toString()' string.concatenation.in.loops.only.option=Only warn if string is repeatedly appended string.concatenation.inside.string.buffer.append.replace.quickfix=Replace with chained 'append()' calls -string.equals.empty.string.replace.quickfix=Replace with 'length()==0' -string.equals.empty.string.replace.quickfix2=Replace with 'isEmpty()' +string.equals.empty.string.quickfix=Replace with 'length()==0' +string.equals.empty.string.isempty.quickfix=Replace with 'isEmpty()' tail.recursion.replace.quickfix=Replace tail recursion with iteration if.statement.with.too.many.branches.max.option=Maximum number of branches: if.statement.with.too.many.branches.problem.descriptor='#ref' has too many branches ({0}) #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConcatenationInsideStringBufferAppendInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConcatenationInsideStringBufferAppendInspection.java index ccb0f3f18ba0..ce7c82388a84 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConcatenationInsideStringBufferAppendInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConcatenationInsideStringBufferAppendInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2012 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. @@ -19,6 +19,7 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; @@ -27,18 +28,14 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; - -public class StringConcatenationInsideStringBufferAppendInspection - extends BaseInspection { +public class StringConcatenationInsideStringBufferAppendInspection extends BaseInspection { @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "string.concatenation.inside.string.buffer.append.display.name"); + return InspectionGadgetsBundle.message("string.concatenation.inside.string.buffer.append.display.name"); } @Override @@ -51,9 +48,7 @@ public class StringConcatenationInsideStringBufferAppendInspection public String buildErrorString(Object... infos) { final PsiClass aClass = (PsiClass)infos[0]; final String className = aClass.getName(); - return InspectionGadgetsBundle.message( - "string.concatenation.inside.string.buffer.append.problem.descriptor", - className); + return InspectionGadgetsBundle.message("string.concatenation.inside.string.buffer.append.problem.descriptor", className); } @Override @@ -66,8 +61,7 @@ public class StringConcatenationInsideStringBufferAppendInspection return new ReplaceWithChainedAppendFix(); } - private static class ReplaceWithChainedAppendFix - extends InspectionGadgetsFix { + private static class ReplaceWithChainedAppendFix extends InspectionGadgetsFix { @NotNull public String getName() { @@ -76,153 +70,115 @@ public class StringConcatenationInsideStringBufferAppendInspection } @Override - public void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { + public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiElement methodNameElement = descriptor.getPsiElement(); - final PsiReferenceExpression methodExpression = - (PsiReferenceExpression)methodNameElement.getParent(); + final PsiReferenceExpression methodExpression = (PsiReferenceExpression)methodNameElement.getParent(); if (methodExpression == null) { return; } - final PsiMethodCallExpression methodCallExpression = - (PsiMethodCallExpression)methodExpression.getParent(); + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)methodExpression.getParent(); if (methodCallExpression == null) { return; } - final PsiExpressionList argumentList = - methodCallExpression.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - final PsiExpression argument = arguments[0]; - final boolean useStringValueOf; final PsiMethod method = methodCallExpression.resolveMethod(); if (method == null) { - useStringValueOf = false; + return; } - else { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass == null) { - useStringValueOf = false; - } - else { - final String qualifiedName = containingClass.getQualifiedName(); - if (qualifiedName == null) { - useStringValueOf = false; - } - else { - useStringValueOf = !qualifiedName.equals( - CommonClassNames.JAVA_LANG_STRING_BUFFER) && - !qualifiedName.equals(CommonClassNames.JAVA_LANG_STRING_BUILDER); - } - } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; } - final List expressions = - findConcatenationComponents(argument, useStringValueOf); - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); + final String qualifiedName = containingClass.getQualifiedName(); + if (qualifiedName == null) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (qualifier == null) { return; } - @NonNls final StringBuffer newExpressionBuffer = new StringBuffer(); - newExpressionBuffer.append(qualifier.getText()); - for (String expression : expressions) { - newExpressionBuffer.append(".append("); - newExpressionBuffer.append(expression); - newExpressionBuffer.append(')'); + final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); + final PsiExpression[] arguments = argumentList.getExpressions(); + final PsiExpression argument = arguments[0]; + final boolean useStringValueOf; + useStringValueOf = !qualifiedName.equals(CommonClassNames.JAVA_LANG_STRING_BUFFER) && + !qualifiedName.equals(CommonClassNames.JAVA_LANG_STRING_BUILDER); + @NonNls final StringBuilder newExpressionBuffer = + buildAppendExpression(argument, useStringValueOf, new StringBuilder(qualifier.getText())); + if (newExpressionBuffer == null) { + return; } - final String newExpression = newExpressionBuffer.toString(); - replaceExpression(methodCallExpression, newExpression); + replaceExpression(methodCallExpression, newExpressionBuffer.toString()); } - private static List findConcatenationComponents( - PsiExpression concatenation, boolean useStringValueOf) - throws IncorrectOperationException { - final List out = new ArrayList(); - findConcatenationComponents(concatenation, out, useStringValueOf); - return out; - } - - private static void findConcatenationComponents( - PsiExpression concatenation, @NonNls List out, - boolean useStringValueOf) + @Nullable + private static StringBuilder buildAppendExpression(PsiExpression concatenation, boolean useStringValueOf, @NonNls StringBuilder out) throws IncorrectOperationException { final PsiType type = concatenation.getType(); - if (concatenation instanceof PsiBinaryExpression) { - if (type != null && type.equalsToText( - CommonClassNames.JAVA_LANG_STRING)) { - PsiBinaryExpression binaryExpression = - (PsiBinaryExpression)concatenation; - PsiExpression lhs = binaryExpression.getLOperand(); - PsiExpression rhs = binaryExpression.getROperand(); - assert rhs != null; - if (!PsiUtil.isConstantExpression(rhs)) { - findConcatenationComponents(lhs, out, useStringValueOf); - findConcatenationComponents(rhs, out, useStringValueOf); - return; - } - final StringBuffer builder = - new StringBuffer(rhs.getText()); - while (lhs instanceof PsiBinaryExpression) { - final PsiType lhsType = lhs.getType(); - if (lhsType == null || - !lhsType.equalsToText( - CommonClassNames.JAVA_LANG_STRING)) { - break; + if (type == null) { + return null; + } + if (concatenation instanceof PsiPolyadicExpression && type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)concatenation; + final PsiExpression[] operands = polyadicExpression.getOperands(); + boolean isConstant = true; + boolean isString = false; + final StringBuilder builder = new StringBuilder(); + for (PsiExpression operand : operands) { + if (isConstant && PsiUtil.isConstantExpression(operand)) { + if (builder.length() != 0) { + builder.append('+'); } - binaryExpression = (PsiBinaryExpression)lhs; - rhs = binaryExpression.getROperand(); - assert rhs != null; - if (!PsiUtil.isConstantExpression(rhs)) { - findConcatenationComponents(lhs, out, useStringValueOf); - out.add(builder.toString()); - return; + final PsiType operandType = operand.getType(); + if (operandType != null && operandType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + isString = true; } - lhs = binaryExpression.getLOperand(); - builder.insert(0, " + "); - builder.insert(0, rhs.getText()); - } - if (PsiUtil.isConstantExpression(lhs)) { - builder.insert(0, " + "); - builder.insert(0, lhs.getText()); - out.add(builder.toString()); + builder.append(operand.getText()); } else { - findConcatenationComponents(lhs, out, useStringValueOf); - out.add(builder.toString()); + isConstant = false; + if (builder.length() != 0) { + append(builder, useStringValueOf && !isString, out); + builder.setLength(0); + } + buildAppendExpression(operand, useStringValueOf, out); } - return; + } + if (builder.length() != 0) { + append(builder, false, out); } } else if (concatenation instanceof PsiParenthesizedExpression) { - final PsiParenthesizedExpression parenthesizedExpression = - (PsiParenthesizedExpression)concatenation; - final PsiExpression expression = - parenthesizedExpression.getExpression(); + final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)concatenation; + final PsiExpression expression = parenthesizedExpression.getExpression(); if (expression != null) { - out.add(expression.getText()); + return buildAppendExpression(expression, useStringValueOf, out); } - return; - } - if (useStringValueOf && type != null && - !type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { - out.add("String.valueOf(" + concatenation.getText() + ')'); } else { - out.add(concatenation.getText()); + append(concatenation.getText(), useStringValueOf && !type.equalsToText(CommonClassNames.JAVA_LANG_STRING), out); } + return out; + } + + private static void append(CharSequence text, boolean useStringValueOf, StringBuilder out) { + out.append(".append("); + if (useStringValueOf) { + out.append("String.valueOf(").append(text).append(')'); + } + else { + out.append(text); + } + out.append(')'); } } - private static class StringConcatenationInsideStringBufferAppendVisitor - extends BaseInspectionVisitor { + private static class StringConcatenationInsideStringBufferAppendVisitor extends BaseInspectionVisitor { @Override - public void visitMethodCallExpression( - PsiMethodCallExpression expression) { + public void visitMethodCallExpression(PsiMethodCallExpression expression) { super.visitMethodCallExpression(expression); - final PsiReferenceExpression methodExpression = - expression.getMethodExpression(); - @NonNls final String methodName = - methodExpression.getReferenceName(); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + @NonNls final String methodName = methodExpression.getReferenceName(); if (!"append".equals(methodName)) { return; } @@ -251,20 +207,22 @@ public class StringConcatenationInsideStringBufferAppendInspection } final Project project = containingClass.getProject(); final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - final PsiClass appendableClass = - psiFacade.findClass("java.lang.Appendable", - GlobalSearchScope.allScope(project)); + final PsiClass appendableClass = psiFacade.findClass("java.lang.Appendable", GlobalSearchScope.allScope(project)); if (appendableClass == null) { return; } - if (!containingClass.isInheritor(appendableClass, true)) { + if (!InheritanceUtil.isInheritorOrSelf(containingClass, appendableClass, true)) { return; } registerMethodCallError(expression, containingClass); } private static boolean isConcatenation(PsiExpression expression) { - if (!(expression instanceof PsiBinaryExpression)) { + if (expression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression; + return isConcatenation(parenthesizedExpression.getExpression()); + } + if (!(expression instanceof PsiPolyadicExpression)) { return false; } if (PsiUtil.isConstantExpression(expression)) { diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java index c53bfcd65c66..9d239902e2c8 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2012 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. @@ -36,8 +36,7 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "string.equals.empty.string.display.name"); + return InspectionGadgetsBundle.message("string.equals.empty.string.display.name"); } @Override @@ -57,8 +56,7 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { return new StringEqualsEmptyStringFix(useIsEmpty); } - private static class StringEqualsEmptyStringFix - extends InspectionGadgetsFix { + private static class StringEqualsEmptyStringFix extends InspectionGadgetsFix { private final boolean useIsEmpty; @@ -69,27 +67,21 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { @NotNull public String getName() { if (useIsEmpty) { - return InspectionGadgetsBundle.message( - "string.equals.empty.string.replace.quickfix2"); + return InspectionGadgetsBundle.message("string.equals.empty.string.isempty.quickfix"); } else { - return InspectionGadgetsBundle.message( - "string.equals.empty.string.replace.quickfix"); + return InspectionGadgetsBundle.message("string.equals.empty.string.quickfix"); } } @Override - public void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { - final PsiIdentifier name = - (PsiIdentifier)descriptor.getPsiElement(); - final PsiReferenceExpression expression = - (PsiReferenceExpression)name.getParent(); + public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + final PsiIdentifier name = (PsiIdentifier)descriptor.getPsiElement(); + final PsiReferenceExpression expression = (PsiReferenceExpression)name.getParent(); if (expression == null) { return; } - final PsiMethodCallExpression call = - (PsiMethodCallExpression)expression.getParent(); + final PsiMethodCallExpression call = (PsiMethodCallExpression)expression.getParent(); final PsiExpressionList argumentList = call.getArgumentList(); final PsiExpression[] arguments = argumentList.getExpressions(); if (arguments.length == 0) { @@ -98,42 +90,55 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { final PsiExpression qualifier = expression.getQualifierExpression(); final PsiExpression argument = arguments[0]; final String variableText; + final boolean addNullCheck; if (ExpressionUtils.isEmptyStringLiteral(argument)) { variableText = getRemainingText(qualifier); + addNullCheck = false; } else { variableText = getRemainingText(argument); + addNullCheck = true; + } + StringBuilder newExpression; + if (addNullCheck) { + newExpression = new StringBuilder(variableText); + newExpression.append("!=null&&"); + } else { + newExpression = new StringBuilder(""); } final PsiElement parent = call.getParent(); + final PsiExpression expressionToReplace; if (parent instanceof PsiExpression) { final PsiExpression parentExpression = (PsiExpression)parent; if (BoolUtils.isNegation(parentExpression)) { + expressionToReplace = parentExpression; if (useIsEmpty) { - replaceExpression(parentExpression, - '!' + variableText + ".isEmpty()"); + newExpression.append('!').append(variableText).append(".isEmpty()"); } else { - replaceExpression(parentExpression, - variableText + ".length()!=0"); + newExpression.append(variableText).append(".length()!=0"); } } else { + expressionToReplace = call; if (useIsEmpty) { - replaceExpression(call, variableText + ".isEmpty()"); + newExpression.append(variableText).append(".isEmpty()"); } else { - replaceExpression(call, variableText + ".length()==0"); + newExpression.append(variableText).append(".length()==0"); } } } else { + expressionToReplace = call; if (useIsEmpty) { - replaceExpression(call, variableText + ".isEmpty()"); + newExpression.append(variableText).append(".isEmpty()"); } else { - replaceExpression(call, variableText + ".length()==0"); + newExpression.append(variableText).append(".length()==0"); } } + replaceExpression(expressionToReplace, newExpression.toString()); } private String getRemainingText(PsiExpression expression) { @@ -143,22 +148,16 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { } // to replace stringBuffer.toString().equals("") with // stringBuffer.length() == 0 - final PsiMethodCallExpression callExpression = - (PsiMethodCallExpression)expression; - final PsiReferenceExpression methodExpression = - callExpression.getMethodExpression(); - final String referenceName = - methodExpression.getReferenceName(); - final PsiExpression qualifierExpression = - methodExpression.getQualifierExpression(); + final PsiMethodCallExpression callExpression = (PsiMethodCallExpression)expression; + final PsiReferenceExpression methodExpression = callExpression.getMethodExpression(); + final String referenceName = methodExpression.getReferenceName(); + final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); if (qualifierExpression == null) { return expression.getText(); } final PsiType type = qualifierExpression.getType(); - if (HardcodedMethodConstants.TO_STRING.equals(referenceName) && - type != null && (type.equalsToText( - CommonClassNames.JAVA_LANG_STRING_BUFFER) || - type.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUILDER))) { + if (HardcodedMethodConstants.TO_STRING.equals(referenceName) && type != null && (type.equalsToText( + CommonClassNames.JAVA_LANG_STRING_BUFFER) || type.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUILDER))) { return qualifierExpression.getText(); } else { @@ -172,17 +171,13 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { return new StringEqualsEmptyStringVisitor(); } - private static class StringEqualsEmptyStringVisitor - extends BaseInspectionVisitor { + private static class StringEqualsEmptyStringVisitor extends BaseInspectionVisitor { @Override - public void visitMethodCallExpression( - @NotNull PsiMethodCallExpression call) { + public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { super.visitMethodCallExpression(call); - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); - @NonNls final String methodName = - methodExpression.getReferenceName(); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + @NonNls final String methodName = methodExpression.getReferenceName(); if (!"equals".equals(methodName)) { return; } @@ -194,13 +189,12 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { final PsiElement context = call.getParent(); final boolean useIsEmpty = PsiUtil.isLanguageLevel6OrHigher(call); if (!useIsEmpty && context instanceof PsiExpressionStatement) { - //cheesy, but necessary, because otherwise the quickfix will + // cheesy, but necessary, because otherwise the quickfix will // produce uncompilable code (out of merely incorrect code). return; } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); final PsiExpression argument = arguments[0]; if (ExpressionUtils.isEmptyStringLiteral(qualifier)) { final PsiType type = argument.getType(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/NullCheck.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/NullCheck.after.java new file mode 100644 index 000000000000..7ee108da4344 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/NullCheck.after.java @@ -0,0 +1,8 @@ +package com.siyeh.igfixes.performance.replace_with_isempty; + +public class NullCheck { + + void foo(String s) { + if (s != null && s.isEmpty()) {} + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/NullCheck.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/NullCheck.java new file mode 100644 index 000000000000..35513a1c110e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/NullCheck.java @@ -0,0 +1,8 @@ +package com.siyeh.igfixes.performance.replace_with_isempty; + +public class NullCheck { + + void foo(String s) { + if ("".equals(s)) {} + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/Simple.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/Simple.after.java new file mode 100644 index 000000000000..d7e73b2cf160 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/Simple.after.java @@ -0,0 +1,9 @@ +package com.siyeh.igfixes.performance.replace_with_isempty; + +public class Simple { + + void foo(String s) { + if (s.isEmpty()) {} + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/Simple.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/Simple.java new file mode 100644 index 000000000000..8b1948e0e6ec --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_isempty/Simple.java @@ -0,0 +1,9 @@ +package com.siyeh.igfixes.performance.replace_with_isempty; + +public class Simple { + + void foo(String s) { + if (s.equals("")) {} + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_concatenation_inside_string_buffer_append/StringConcatenationInsideStringBufferAppend.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_concatenation_inside_string_buffer_append/StringConcatenationInsideStringBufferAppend.java new file mode 100644 index 000000000000..aa2ad6f66c74 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_concatenation_inside_string_buffer_append/StringConcatenationInsideStringBufferAppend.java @@ -0,0 +1,26 @@ +package com.siyeh.igtest.performance.string_concatenation_inside_string_buffer_append; + +public class StringConcatenationInsideStringBufferAppend { + + private String s; + + void foo(StringBuffer buffer) { + buffer.append("asdf" + s + "asdf"); + buffer.append("asdf" + s); + buffer.append("asdf" + "asdf"); + } + + void bar(StringBuilder builder) { + builder.append("asdf" + s + "asdf"); + builder.append("asdf" + s); + builder.append("asdf" + "asdf"); + } + + /* + // java.lang.Appendable not in mock jdk + void appendable(Appendable appendable) throws IOException { + appendable.append("asdf" + s); + appendable.append((s + "asdf")); + } + */ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_concatenation_inside_string_buffer_append/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_concatenation_inside_string_buffer_append/expected.xml new file mode 100644 index 000000000000..4716b8cbf3e0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_concatenation_inside_string_buffer_append/expected.xml @@ -0,0 +1,31 @@ + + + + StringConcatenationInsideStringBufferAppend.java + 10 + String concatenation as argument to 'StringBuffer.append()' call + String concatenation as argument to <code>StringBuffer.append()</code> call #loc + + + + StringConcatenationInsideStringBufferAppend.java + 11 + String concatenation as argument to 'StringBuffer.append()' call + String concatenation as argument to <code>StringBuffer.append()</code> call #loc + + + + StringConcatenationInsideStringBufferAppend.java + 16 + String concatenation as argument to 'StringBuffer.append()' call + String concatenation as argument to <code>StringBuilder.append()</code> call #loc + + + + StringConcatenationInsideStringBufferAppend.java + 17 + String concatenation as argument to 'StringBuffer.append()' call + String concatenation as argument to <code>StringBuilder.append()</code> call #loc + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/StringEqualsEmptyStringFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/StringEqualsEmptyStringFixTest.java new file mode 100644 index 000000000000..a42fccbda5a6 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/StringEqualsEmptyStringFixTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012 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.fixes.performance; + +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.IGQuickFixesTestCase; +import com.siyeh.ig.performance.StringEqualsEmptyStringInspection; + +public class StringEqualsEmptyStringFixTest extends IGQuickFixesTestCase { + + @Override + public void setUp() throws Exception { + super.setUp(); + myFixture.enableInspections(new StringEqualsEmptyStringInspection()); + myRelativePath = "performance/replace_with_isempty"; + myDefaultHint = InspectionGadgetsBundle.message("string.equals.empty.string.isempty.quickfix"); + } + + public void testSimple() { doTest(); } + public void testNullCheck() { doTest(); } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/StringConcatenationInsideStringBufferAppendInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/StringConcatenationInsideStringBufferAppendInspectionTest.java new file mode 100644 index 000000000000..b7d638b83c6b --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/StringConcatenationInsideStringBufferAppendInspectionTest.java @@ -0,0 +1,11 @@ +package com.siyeh.ig.performance; + +import com.siyeh.ig.IGInspectionTestCase; + +public class StringConcatenationInsideStringBufferAppendInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + doTest("com/siyeh/igtest/performance/string_concatenation_inside_string_buffer_append", + new StringConcatenationInsideStringBufferAppendInspection()); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java index 24644c33ee5e..942a85aa1ed0 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -28,7 +28,6 @@ import com.intellij.designer.DesignerToolWindowManager; import com.intellij.designer.componentTree.TreeComponentDecorator; import com.intellij.designer.designSurface.*; import com.intellij.designer.designSurface.selection.DirectionResizePoint; -import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator; import com.intellij.designer.designSurface.selection.ResizeSelectionDecorator; import com.intellij.designer.designSurface.tools.ComponentCreationFactory; import com.intellij.designer.designSurface.tools.CreationTool; diff --git a/plugins/android/src/org/jetbrains/android/AndroidPlugin.java b/plugins/android/src/org/jetbrains/android/AndroidPlugin.java index 289ed66eba41..77af95dac61d 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidPlugin.java +++ b/plugins/android/src/org/jetbrains/android/AndroidPlugin.java @@ -16,7 +16,7 @@ package org.jetbrains.android; import com.intellij.openapi.components.ApplicationComponent; -import org.jetbrains.android.sdk.AndroidSdk; +import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.annotations.NotNull; /** @@ -33,6 +33,6 @@ public class AndroidPlugin implements ApplicationComponent { } public void disposeComponent() { - AndroidSdk.terminateDdmlib(); + AndroidSdkData.terminateDdmlib(); } } diff --git a/plugins/android/src/org/jetbrains/android/actions/AndroidEnableDdmsAction.java b/plugins/android/src/org/jetbrains/android/actions/AndroidEnableDdmsAction.java index 50d3973d1850..c2502b33963b 100644 --- a/plugins/android/src/org/jetbrains/android/actions/AndroidEnableDdmsAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/AndroidEnableDdmsAction.java @@ -25,7 +25,7 @@ import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.logcat.AndroidLogcatToolWindowFactory; -import org.jetbrains.android.sdk.AndroidSdk; +import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.android.util.AndroidBundle; import javax.swing.*; @@ -72,7 +72,7 @@ public class AndroidEnableDdmsAction extends ToggleAction { hidden = true; toolWindow.hide(null); } - AndroidSdk.terminateDdmlib(); + AndroidSdkData.terminateDdmlib(); if (hidden) { toolWindow.show(null); } diff --git a/plugins/android/src/org/jetbrains/android/actions/AndroidRunSdkToolAction.java b/plugins/android/src/org/jetbrains/android/actions/AndroidRunSdkToolAction.java index bcde59b09cb9..26f5889d55f1 100644 --- a/plugins/android/src/org/jetbrains/android/actions/AndroidRunSdkToolAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/AndroidRunSdkToolAction.java @@ -10,7 +10,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; import org.jetbrains.android.facet.AndroidFacet; -import org.jetbrains.android.sdk.AndroidSdk; +import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.annotations.NotNull; @@ -39,9 +39,9 @@ public abstract class AndroidRunSdkToolAction extends AnAction { assert facets.size() > 0; Set sdkSet = new HashSet(); for (AndroidFacet facet : facets) { - AndroidSdk sdk = facet.getConfiguration().getAndroidSdk(); - if (sdk != null) { - sdkSet.add(sdk.getLocation()); + AndroidSdkData sdkData = facet.getConfiguration().getAndroidSdk(); + if (sdkData != null) { + sdkSet.add(sdkData.getLocation()); } } if (sdkSet.size() == 0) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index 47f72c4965a2..60d5385b24eb 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -223,7 +223,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { } final IAndroidTarget target = platform.getTarget(); - final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision(); + final int platformToolsRevision = platform.getSdkData().getPlatformToolsRevision(); String[] resPaths = AndroidCompileUtil.collectResourceDirs(facet, false, myContext); if (resPaths.length <= 0) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java index 81ab22f38125..3d1387a147a2 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java @@ -94,7 +94,7 @@ public class AndroidAutogenerator { } final IAndroidTarget target = platform.getTarget(); - final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision(); + final int platformToolsRevision = platform.getSdkData().getPlatformToolsRevision(); final String[] resPaths = AndroidCompileUtil.collectResourceDirs(facet, false, context); if (resPaths.length == 0) { @@ -419,7 +419,7 @@ public class AndroidAutogenerator { } final IAndroidTarget target = platform.getTarget(); - final String sdkLocation = platform.getSdk().getLocation(); + final String sdkLocation = platform.getSdkData().getLocation(); final String packageName = AndroidUtils.computePackageName(module, file); if (packageName == null) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index 5c48c0ec6b03..05ccfbdce99e 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -530,7 +530,7 @@ public class AndroidCompileUtil { if (collectResCacheDirs) { final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); - final int platformToolsRevision = platform != null ? platform.getSdk().getPlatformToolsRevision() : -1; + final int platformToolsRevision = platform != null ? platform.getSdkData().getPlatformToolsRevision() : -1; if (platformToolsRevision < 0 || platformToolsRevision > 7) { // png cache is supported since platform-tools-r8 diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidIncludingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidIncludingCompiler.java index 8b23db1515a0..3026778ead3b 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidIncludingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidIncludingCompiler.java @@ -93,7 +93,7 @@ public class AndroidIncludingCompiler implements SourceGeneratingCompiler { for (AndroidFacet depFacet : AndroidSdkUtils.getAllAndroidDependencies(module, true)) { final AndroidPlatform platform = depFacet.getConfiguration().getAndroidPlatform(); - final int platformToolsRevision = platform != null ? platform.getSdk().getPlatformToolsRevision() : -1; + final int platformToolsRevision = platform != null ? platform.getSdkData().getPlatformToolsRevision() : -1; if (platformToolsRevision < 0 || platformToolsRevision > 7) { // "including" style building of library projects is deprecated since platform-tools-r8 continue; diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java index fed97f4fb372..bb10c2191d2d 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java @@ -126,7 +126,7 @@ public class AndroidPackagingCompiler implements PackagingCompiler { AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); continue; } - String sdkPath = platform.getSdk().getLocation(); + String sdkPath = platform.getSdkData().getLocation(); String outputPath = AndroidRootUtil.getApkPath(facet); if (outputPath == null) { context.addMessage(CompilerMessageCategory.ERROR, diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java index 16441747814f..e92f51586537 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java @@ -58,7 +58,7 @@ public class AndroidPngFilesCachingCompiler implements SourceGeneratingCompiler continue; } - final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision(); + final int platformToolsRevision = platform.getSdkData().getPlatformToolsRevision(); if (platformToolsRevision > 0 && platformToolsRevision <= 7) { // png files cache is supported since platform-tools-r8 continue; diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java index 0fa0c9428bbc..c8cffcee1b5e 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java @@ -81,7 +81,7 @@ public class AndroidPrecompileTask implements CompileTask { } final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); - final int platformToolsRevision = platform != null ? platform.getSdk().getPlatformToolsRevision() : -1; + final int platformToolsRevision = platform != null ? platform.getSdkData().getPlatformToolsRevision() : -1; LOG.debug("Platform-tools revision for module " + module.getName() + " is " + platformToolsRevision); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java index ffe8300de363..7100a24c95b6 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java @@ -129,7 +129,7 @@ public class AndroidProguardCompiler implements ClassPostProcessingCompiler { } } - final String sdkPath = FileUtil.toSystemDependentName(platform.getSdk().getLocation()); + final String sdkPath = FileUtil.toSystemDependentName(platform.getSdkData().getLocation()); final VirtualFile outputDir = AndroidDexCompiler.getOutputDirectoryForDex(module); final String outputJarOsPath = FileUtil.toSystemDependentName(outputDir.getPath() + '/' + PROGUARD_OUTPUT_JAR_NAME); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java index c562ee980156..696dbb807340 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java @@ -87,7 +87,7 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } final IAndroidTarget target = platform.getTarget(); - final String sdkLocation = platform.getSdk().getLocation(); + final String sdkLocation = platform.getSdkData().getLocation(); final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); assert resourceDirPath != null; diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java index 5bda5d89b540..2db81a6c665d 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java @@ -78,7 +78,7 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null; String[] resourcesDirPaths = AndroidCompileUtil.collectResourceDirs(facet, true, context); final IAndroidTarget target = platform.getTarget(); - final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision(); + final int platformToolsRevision = platform.getSdkData().getPlatformToolsRevision(); if (resourcesDirPaths.length == 0) { context.addMessage(CompilerMessageCategory.WARNING, "Resource directory not found for module " + module.getName(), diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index d27208869658..9eee93725d1b 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -419,7 +419,7 @@ public class AndroidApkBuilder { } // we exclude sources of library modules automatically for tools r7 or previous - return platform.getSdk().getPlatformToolsRevision() > 7; + return platform.getSdkData().getPlatformToolsRevision() > 7; } private static void writeStandardSourceFolderResources(Collection resources, diff --git a/plugins/android/src/org/jetbrains/android/converter/AndroidModuleConverter1.java b/plugins/android/src/org/jetbrains/android/converter/AndroidModuleConverter1.java index 3abe6d2285ee..2e589c3391bf 100644 --- a/plugins/android/src/org/jetbrains/android/converter/AndroidModuleConverter1.java +++ b/plugins/android/src/org/jetbrains/android/converter/AndroidModuleConverter1.java @@ -71,10 +71,10 @@ public class AndroidModuleConverter1 extends ConversionProcessor if (androidPlatform != null) { - Sdk androidSdk = AndroidSdkUtils.findAppropriateAndroidPlatform(androidPlatform.getTarget(), androidPlatform.getSdk()); + Sdk androidSdk = AndroidSdkUtils.findAppropriateAndroidPlatform(androidPlatform.getTarget(), androidPlatform.getSdkData()); if (androidSdk == null) { - androidSdk = AndroidSdkUtils.createNewAndroidPlatform(androidPlatform.getTarget(), androidPlatform.getSdk().getLocation(), false); + androidSdk = AndroidSdkUtils.createNewAndroidPlatform(androidPlatform.getTarget(), androidPlatform.getSdkData().getLocation(), false); final SdkModificator modificator = androidSdk.getSdkModificator(); for (OrderRootType type : OrderRootType.getAllTypes()) { diff --git a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java index 5cd52bc683fa..ef5dbc269b2d 100644 --- a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java +++ b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java @@ -195,7 +195,7 @@ class ApkStep extends ExportSignedPackageWizardStep { private void createAndAlignApk(final String apkPath) { AndroidPlatform platform = myWizard.getFacet().getConfiguration().getAndroidPlatform(); assert platform != null; - String sdkPath = platform.getSdk().getLocation(); + String sdkPath = platform.getSdkData().getLocation(); String zipAlignPath = sdkPath + File.separatorChar + AndroidSdkUtils.toolPath(SdkConstants.FN_ZIPALIGN); File zipalign = new File(zipAlignPath); final boolean runZipAlign = zipalign.isFile(); diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java index ccc482bebdb9..bc00911c7862 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java @@ -211,7 +211,7 @@ public class AndroidFacet extends Facet { public AndroidDebugBridge getDebugBridge() { AndroidPlatform platform = getConfiguration().getAndroidPlatform(); if (platform != null) { - return platform.getSdk().getDebugBridge(getModule().getProject()); + return platform.getSdkData().getDebugBridge(getModule().getProject()); } return null; } @@ -376,10 +376,10 @@ public class AndroidFacet extends Facet { public AvdManager getAvdManager() throws AvdsNotSupportedException, AndroidLocation.AndroidLocationException { if (myAvdManager == null) { AndroidPlatform platform = getConfiguration().getAndroidPlatform(); - AndroidSdk sdk = platform != null ? platform.getSdk() : null; + AndroidSdkData sdkData = platform != null ? platform.getSdkData() : null; Project project = getModule().getProject(); - if (sdk != null) { - SdkManager sdkManager = sdk.getSdkManager(); + if (sdkData != null) { + SdkManager sdkManager = sdkData.getSdkManager(); myAvdManager = new AvdManager(sdkManager, AndroidSdkUtils.getSdkLog(project)); } else { @@ -392,7 +392,7 @@ public class AndroidFacet extends Facet { public void launchEmulator(@Nullable final String avdName, @NotNull final String commands, @Nullable ProcessHandler handler) { AndroidPlatform platform = getConfiguration().getAndroidPlatform(); if (platform != null) { - final String emulatorPath = platform.getSdk().getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_EMULATOR); + final String emulatorPath = platform.getSdkData().getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_EMULATOR); final GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.setExePath(FileUtil.toSystemDependentName(emulatorPath)); if (avdName != null) { diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java index 1b7d639ea8eb..2684e49eced7 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java @@ -31,7 +31,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jdom.Element; import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.sdk.AndroidSdk; +import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.android.sdk.AndroidSdkAdditionalData; import org.jetbrains.android.sdk.AndroidSdkType; import org.jetbrains.annotations.NonNls; @@ -122,9 +122,9 @@ public class AndroidFacetConfiguration implements FacetConfiguration { } @Nullable - public AndroidSdk getAndroidSdk() { + public AndroidSdkData getAndroidSdk() { AndroidPlatform platform = getAndroidPlatform(); - return platform != null ? platform.getSdk() : null; + return platform != null ? platform.getSdkData() : null; } @Nullable diff --git a/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowView.java b/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowView.java index a1a5079dee9f..3d385e246ef2 100644 --- a/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowView.java +++ b/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowView.java @@ -409,7 +409,7 @@ public abstract class AndroidLogcatToolWindowView implements Disposable { private void updateDevices() { AndroidPlatform platform = getAndroidPlatform(myProject); if (platform != null) { - final AndroidDebugBridge debugBridge = platform.getSdk().getDebugBridge(myProject); + final AndroidDebugBridge debugBridge = platform.getSdkData().getDebugBridge(myProject); if (debugBridge != null) { IDevice[] devices = debugBridge.getDevices(); Object temp = myDeviceCombo.getSelectedItem(); diff --git a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java index f5c8a8910752..ebd7a68326ae 100644 --- a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java +++ b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporterBase.java @@ -618,11 +618,11 @@ public abstract class AndroidFacetImporterBase extends FacetImporter parsedSdks) { + @Nullable Map parsedSdks) { VirtualFile[] files = model != null ? model.getFiles(OrderRootType.CLASSES) : library.getFiles(OrderRootType.CLASSES); Set jarPaths = new HashSet(); VirtualFile frameworkLibrary = null; @@ -119,16 +119,16 @@ public class AndroidPlatform { if (sdkDir == null) return null; } String sdkPath = sdkDir.getPath(); - AndroidSdk sdk = parsedSdks != null ? parsedSdks.get(sdkPath) : null; - if (sdk == null) { - sdk = AndroidSdk.parse(sdkPath, new EmptySdkLog()); - if (sdk == null) return null; + AndroidSdkData sdkData = parsedSdks != null ? parsedSdks.get(sdkPath) : null; + if (sdkData == null) { + sdkData = AndroidSdkData.parse(sdkPath, new EmptySdkLog()); + if (sdkData == null) return null; if (parsedSdks != null) { - parsedSdks.put(sdkPath, sdk); + parsedSdks.put(sdkPath, sdkData); } } IAndroidTarget resultTarget = null; - for (IAndroidTarget target : sdk.getTargets()) { + for (IAndroidTarget target : sdkData.getTargets()) { String targetsFrameworkLibPath = PathUtil.getCanonicalPath(target.getPath(IAndroidTarget.ANDROID_JAR)); if (frameworkLibrary.getPath().equals(targetsFrameworkLibPath)) { if (target.isPlatform()) { @@ -153,7 +153,7 @@ public class AndroidPlatform { } } if (resultTarget != null) { - return new AndroidPlatform(sdk, resultTarget); + return new AndroidPlatform(sdkData, resultTarget); } } } @@ -167,7 +167,7 @@ public class AndroidPlatform { AndroidPlatform platform = (AndroidPlatform)o; - if (!mySdk.equals(platform.mySdk)) return false; + if (!mySdkData.equals(platform.mySdkData)) return false; if (!myTarget.equals(platform.myTarget)) return false; return true; @@ -175,7 +175,7 @@ public class AndroidPlatform { @Override public int hashCode() { - int result = mySdk.hashCode(); + int result = mySdkData.hashCode(); result = 31 * result + myTarget.hashCode(); return result; } diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkAdditionalData.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkAdditionalData.java index 11f510bc4a64..9b0650ce186c 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkAdditionalData.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkAdditionalData.java @@ -109,8 +109,8 @@ public class AndroidSdkAdditionalData implements SdkAdditionalData { } @Nullable - public IAndroidTarget getBuildTarget(@NotNull AndroidSdk sdkObject) { - return myBuildTarget != null ? sdkObject.findTargetByHashString(myBuildTarget) : null; + public IAndroidTarget getBuildTarget(@NotNull AndroidSdkData sdkData) { + return myBuildTarget != null ? sdkData.findTargetByHashString(myBuildTarget) : null; } @Nullable diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java index 1e7c2e7aca3c..19cb6ecf3e13 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java @@ -106,7 +106,7 @@ public class AndroidSdkConfigurable implements AdditionalDataConfigurable { } final AndroidSdkAdditionalData androidData = (AndroidSdkAdditionalData)data; AndroidPlatform platform = androidData.getAndroidPlatform(); - myForm.init(androidData.getJavaSdk(), mySdk, platform != null ? androidData.getBuildTarget(platform.getSdk()) : null); + myForm.init(androidData.getJavaSdk(), mySdk, platform != null ? androidData.getBuildTarget(platform.getSdkData()) : null); } @Override diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java index f51c00b5a798..15bfff802867 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java @@ -134,8 +134,8 @@ class AndroidSdkConfigurableForm { } mySdkLocation = androidSdk != null ? androidSdk.getHomePath() : null; - AndroidSdk androidSdkObject = mySdkLocation != null ? AndroidSdk.parse(mySdkLocation, new EmptySdkLog()) : null; - updateBuildTargets(androidSdkObject); + AndroidSdkData androidSdkData = mySdkLocation != null ? AndroidSdkData.parse(mySdkLocation, new EmptySdkLog()) : null; + updateBuildTargets(androidSdkData); if (buildTarget != null) { for (int i = 0; i < myBuildTargetsModel.getSize(); i++) { @@ -157,11 +157,11 @@ class AndroidSdkConfigurableForm { } } - private void updateBuildTargets(AndroidSdk androidSdk) { + private void updateBuildTargets(AndroidSdkData androidSdkData) { myBuildTargetsModel.removeAllElements(); - if (androidSdk != null) { - for (IAndroidTarget target : androidSdk.getTargets()) { + if (androidSdkData != null) { + for (IAndroidTarget target : androidSdkData.getTargets()) { myBuildTargetsModel.addElement(target); } } diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java similarity index 96% rename from plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java rename to plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java index 17b78df7446b..e7e71b61bf4e 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java @@ -46,8 +46,8 @@ import java.util.Map; /** * @author Eugene.Kudelevsky */ -public class AndroidSdk { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.sdk.AndroidSdk"); +public class AndroidSdkData { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.sdk.AndroidSdkData"); private static volatile boolean myDdmLibInitialized = false; @@ -63,7 +63,7 @@ public class AndroidSdk { private final int myPlatformToolsRevision; - public AndroidSdk(@NotNull SdkManager sdkManager, @NotNull String sdkDirOsPath) { + public AndroidSdkData(@NotNull SdkManager sdkManager, @NotNull String sdkDirOsPath) { mySdkManager = sdkManager; final File platformToolsPropFile = @@ -150,31 +150,31 @@ public class AndroidSdk { } @Nullable - public static AndroidSdk parse(@NotNull String path, @NotNull ISdkLog log) { + public static AndroidSdkData parse(@NotNull String path, @NotNull ISdkLog log) { final SdkManager manager = AndroidCommonUtils.createSdkManager(path, log); - return manager != null ? new AndroidSdk(manager, path) : null; + return manager != null ? new AndroidSdkData(manager, path) : null; } @Nullable - public static AndroidSdk parse(@NotNull String path, @NotNull final Component component) { + public static AndroidSdkData parse(@NotNull String path, @NotNull final Component component) { MessageBuildingSdkLog log = new MessageBuildingSdkLog(); - AndroidSdk sdk = parse(path, log); - if (sdk == null) { + AndroidSdkData sdkData = parse(path, log); + if (sdkData == null) { String message = log.getErrorMessage(); if (message.length() > 0) { message = "Android SDK is parsed incorrectly. Parsing log:\n" + message; Messages.showInfoMessage(component, message, CommonBundle.getErrorTitle()); } } - return sdk; + return sdkData; } @Override public boolean equals(Object obj) { if (obj == null) return false; if (obj.getClass() != getClass()) return false; - AndroidSdk sdk = (AndroidSdk)obj; - return FileUtil.pathsEqual(getLocation(), sdk.getLocation()); + AndroidSdkData sdkData = (AndroidSdkData)obj; + return FileUtil.pathsEqual(getLocation(), sdkData.getLocation()); } @Override diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkType.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkType.java index 353d18ea154c..f29bbaaef853 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkType.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkType.java @@ -114,15 +114,15 @@ public class AndroidSdkType extends SdkType implements JavaSdkType { final Sdk jdk = sdkModel.findSdk(name); MessageBuildingSdkLog log = new MessageBuildingSdkLog(); - AndroidSdk sdkObject = AndroidSdk.parse(sdk.getHomePath(), log); + AndroidSdkData sdkData = AndroidSdkData.parse(sdk.getHomePath(), log); - if (sdkObject == null) { + if (sdkData == null) { String errorMessage = log.getErrorMessage().length() > 0 ? log.getErrorMessage() : AndroidBundle.message("cannot.parse.sdk.error"); Messages.showErrorDialog(errorMessage, "SDK Parsing Error"); return false; } - IAndroidTarget[] targets = sdkObject.getTargets(); + IAndroidTarget[] targets = sdkData.getTargets(); if (targets.length == 0) { Messages.showErrorDialog(AndroidBundle.message("no.android.targets.error"), CommonBundle.getErrorTitle()); diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java index 447bd9f62682..812bf196a652 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java @@ -257,7 +257,7 @@ public class AndroidSdkUtils { if (data != null) { final AndroidPlatform androidPlatform = data.getAndroidPlatform(); if (androidPlatform != null) { - result.add(FileUtil.toSystemIndependentName(androidPlatform.getSdk().getLocation())); + result.add(FileUtil.toSystemIndependentName(androidPlatform.getSdkData().getLocation())); } } } @@ -314,7 +314,7 @@ public class AndroidSdkUtils { if (data != null) { final AndroidPlatform androidPlatform = data.getAndroidPlatform(); if (androidPlatform != null) { - final String baseDir = FileUtil.toSystemIndependentName(androidPlatform.getSdk().getLocation()); + final String baseDir = FileUtil.toSystemIndependentName(androidPlatform.getSdkData().getLocation()); if ((sdkDir == null || FileUtil.pathsEqual(baseDir, sdkDir)) && targetHashString.equals(androidPlatform.getTarget().hashString())) { return sdk; @@ -361,11 +361,11 @@ public class AndroidSdkUtils { } private static boolean tryToCreateAndSetAndroidSdk(@NotNull Module module, @NotNull String baseDir, @NotNull String targetHashString) { - final AndroidSdk sdkObject = AndroidSdk.parse(baseDir, new EmptySdkLog()); - if (sdkObject != null) { - final IAndroidTarget target = sdkObject.findTargetByHashString(targetHashString); + final AndroidSdkData sdkData = AndroidSdkData.parse(baseDir, new EmptySdkLog()); + if (sdkData != null) { + final IAndroidTarget target = sdkData.findTargetByHashString(targetHashString); if (target != null) { - final Sdk androidSdk = createNewAndroidPlatform(target, sdkObject.getLocation(), true); + final Sdk androidSdk = createNewAndroidPlatform(target, sdkData.getLocation(), true); if (androidSdk != null) { setSdk(module, androidSdk); return true; @@ -428,18 +428,18 @@ public class AndroidSdkUtils { } @Nullable - public static Sdk findAppropriateAndroidPlatform(@NotNull IAndroidTarget target, @NotNull AndroidSdk sdk) { + public static Sdk findAppropriateAndroidPlatform(@NotNull IAndroidTarget target, @NotNull AndroidSdkData sdkData) { for (Sdk library : ProjectJdkTable.getInstance().getAllJdks()) { final String homePath = library.getHomePath(); if (homePath != null && library.getSdkType().equals(AndroidSdkType.getInstance())) { - final AndroidSdk sdk1 = AndroidSdk.parse(homePath, new EmptySdkLog()); + final AndroidSdkData sdkData1 = AndroidSdkData.parse(homePath, new EmptySdkLog()); - if (sdk1 != null && sdk1.equals(sdk)) { + if (sdkData1 != null && sdkData1.equals(sdkData)) { final AndroidSdkAdditionalData data = (AndroidSdkAdditionalData)library.getSdkAdditionalData(); if (data != null) { - final IAndroidTarget target1 = data.getBuildTarget(sdk1); + final IAndroidTarget target1 = data.getBuildTarget(sdkData1); if (target1 != null && target.hashString().equals(target1.hashString())) { return library; diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidTargetData.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidTargetData.java index 0defc8597a03..4d93a65bbfca 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidTargetData.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidTargetData.java @@ -33,15 +33,15 @@ import java.util.Set; public class AndroidTargetData { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.sdk.AndroidTargetData"); - private final AndroidSdk mySdk; + private final AndroidSdkData mySdkData; private final IAndroidTarget myTarget; private volatile AttributeDefinitions myAttrDefs; private volatile RenderServiceFactory myRenderServiceFactory; private volatile Set myThemes; - public AndroidTargetData(@NotNull AndroidSdk sdk, @NotNull IAndroidTarget target) { - mySdk = sdk; + public AndroidTargetData(@NotNull AndroidSdkData sdkData, @NotNull IAndroidTarget target) { + mySdkData = sdkData; myTarget = target; } @@ -84,7 +84,7 @@ public class AndroidTargetData { if (myThemes == null) { myThemes = new HashSet(); final Module module = facet.getModule(); - final SystemResourceManager systemResourceManager = new SystemResourceManager(facet, new AndroidPlatform(mySdk, myTarget)); + final SystemResourceManager systemResourceManager = new SystemResourceManager(facet, new AndroidPlatform(mySdkData, myTarget)); for (VirtualFile valueResourceDir : systemResourceManager.getResourceSubdirs("values")) { for (final VirtualFile valueResourceFile : valueResourceDir.getChildren()) { diff --git a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java index 197b1b1baa32..f2c6d70270ba 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java @@ -1,25 +1,27 @@ package org.jetbrains.android.uipreview; import com.intellij.openapi.Disposable; - import com.intellij.openapi.progress.ProgressIndicator; - import com.intellij.openapi.ui.Messages; - import com.intellij.openapi.ui.VerticalFlowLayout; - import com.intellij.openapi.util.Disposer; - import com.intellij.ui.HyperlinkLabel; - import com.intellij.ui.components.JBLabel; - import com.intellij.util.ui.AsyncProcessIcon; - import org.jetbrains.annotations.NonNls; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.VerticalFlowLayout; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Pair; +import com.intellij.ui.HyperlinkLabel; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.ui.AsyncProcessIcon; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; - import javax.swing.*; - import javax.swing.border.EmptyBorder; - import javax.swing.event.HyperlinkEvent; - import javax.swing.event.HyperlinkListener; - import java.awt.*; - import java.awt.image.BufferedImage; - import java.util.ArrayList; - import java.util.List; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; /** * @author Eugene.Kudelevsky @@ -29,12 +31,11 @@ public class AndroidLayoutPreviewPanel extends JPanel implements Disposable { private static final double MAX_ZOOM_FACTOR = 2.0; private static final double ZOOM_STEP = 1.25; - private RenderingErrorMessage myErrorMessage; - private String myWarnMessage; + private FixableIssueMessage myErrorMessage; + private List myWarnMessages; private BufferedImage myImage; - private final HyperlinkLabel myHyperlinkMessageLabel = new HyperlinkLabel("", Color.BLUE, getBackground(), Color.BLUE); - private final JBLabel myMessageLabel = new JBLabel(); + private final JPanel myMessagesPanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false)); private double myZoomFactor = 1.0; private boolean myZoomToFit = true; @@ -70,16 +71,6 @@ public class AndroidLayoutPreviewPanel extends JPanel implements Disposable { setOpaque(true); myImagePanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.GRAY)); - myHyperlinkMessageLabel.addHyperlinkListener(new HyperlinkListener() { - public void hyperlinkUpdate(final HyperlinkEvent e) { - final Runnable quickFix = myErrorMessage.myQuickFix; - if (quickFix != null && e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - quickFix.run(); - } - } - }); - myHyperlinkMessageLabel.setOpaque(false); - myFileNameLabel.setHorizontalAlignment(SwingConstants.CENTER); myFileNameLabel.setBorder(new EmptyBorder(5, 0, 5, 0)); @@ -104,8 +95,10 @@ public class AndroidLayoutPreviewPanel extends JPanel implements Disposable { ((CardLayout)myProgressIconWrapper.getLayout()).show(myProgressIconWrapper, EMPTY_CARD_NAME); add(titlePanel); - add(myHyperlinkMessageLabel); - add(myMessageLabel); + + myMessagesPanel.setBorder(IdeBorderFactory.createEmptyBorder(0, 5, 0, 5)); + myMessagesPanel.setOpaque(false); + add(myMessagesPanel); add(new MyImagePanelWrapper()); } @@ -148,45 +141,83 @@ public class AndroidLayoutPreviewPanel extends JPanel implements Disposable { repaint(); } - public void setErrorMessage(@Nullable RenderingErrorMessage errorMessage) { + public void setErrorMessage(@Nullable FixableIssueMessage errorMessage) { myErrorMessage = errorMessage; } - public void setWarnMessage(String warnMessage) { - myWarnMessage = warnMessage; + public void setWarnMessages(@Nullable List warnMessages) { + myWarnMessages = warnMessages; } public void update() { myImagePanel.setVisible(true); - - myHyperlinkMessageLabel.setVisible(false); - myMessageLabel.setVisible(false); + myMessagesPanel.removeAll(); if (myErrorMessage != null) { - if (myErrorMessage.myLinkText.length() > 0 || myErrorMessage.myAfterLinkText.length() > 0) { - myHyperlinkMessageLabel.setHyperlinkText(myErrorMessage.myBeforeLinkText, - myErrorMessage.myLinkText, - myErrorMessage.myAfterLinkText); - myHyperlinkMessageLabel.setIcon(Messages.getErrorIcon()); - myHyperlinkMessageLabel.setVisible(true); - } - else { - myMessageLabel.setText("" + myErrorMessage.myBeforeLinkText.replace("\n", "
") + ""); - myMessageLabel.setIcon(Messages.getErrorIcon()); - myMessageLabel.setVisible(true); + showMessage(myErrorMessage, Messages.getErrorIcon()); + } + if (myWarnMessages != null) { + for (FixableIssueMessage warnMessage : myWarnMessages) { + showMessage(warnMessage, Messages.getWarningIcon()); } } - - if (myErrorMessage == null && myWarnMessage != null && myWarnMessage.length() > 0) { - myMessageLabel.setText("" + myWarnMessage.replace("\n", "
") + ""); - myMessageLabel.setIcon(Messages.getWarningIcon()); - myMessageLabel.setVisible(true); - } - + revalidate(); repaint(); } - void updateImageSize() { + private void showMessage(final FixableIssueMessage message, Icon icon) { + if (message.myLinkText.length() > 0 || message.myAfterLinkText.length() > 0) { + final HyperlinkLabel warnLabel = new HyperlinkLabel(); + warnLabel.setOpaque(false); + warnLabel.setHyperlinkText(message.myBeforeLinkText, + message.myLinkText, + message.myAfterLinkText); + warnLabel.setIcon(icon); + + warnLabel.addHyperlinkListener(new HyperlinkListener() { + public void hyperlinkUpdate(final HyperlinkEvent e) { + final Runnable quickFix = message.myQuickFix; + if (quickFix != null && e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + quickFix.run(); + } + } + }); + myMessagesPanel.add(warnLabel); + } + else { + final JBLabel warnLabel = new JBLabel(); + warnLabel.setOpaque(false); + warnLabel.setText("" + message.myBeforeLinkText.replace("\n", "
") + ""); + warnLabel.setIcon(icon); + myMessagesPanel.add(warnLabel); + } + if (message.myAdditionalFixes.size() > 0) { + final JPanel fixesPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0)); + fixesPanel.setBorder(IdeBorderFactory.createEmptyBorder(3, 0, 10, 0)); + fixesPanel.setOpaque(false); + fixesPanel.add(Box.createHorizontalStrut(icon.getIconWidth())); + + for (Pair pair : message.myAdditionalFixes) { + final HyperlinkLabel fixLabel = new HyperlinkLabel(); + fixLabel.setOpaque(false); + fixLabel.setHyperlinkText(pair.getFirst()); + final Runnable fix = pair.getSecond(); + + fixLabel.addHyperlinkListener(new HyperlinkListener() { + @Override + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + fix.run(); + } + } + }); + fixesPanel.add(fixLabel); + } + myMessagesPanel.add(fixesPanel); + } + } + + void updateImageSize() { if (myImage == null) { myImagePanel.setSize(0, 0); } diff --git a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java index efef264c6c30..6ef0b1909197 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java @@ -660,12 +660,12 @@ class AndroidLayoutPreviewToolWindowForm implements Disposable { return null; } - public void setErrorMessage(RenderingErrorMessage errorMessage) { + public void setErrorMessage(FixableIssueMessage errorMessage) { myPreviewPanel.setErrorMessage(errorMessage); } - public void setWarnMessage(String warnMessage) { - myPreviewPanel.setWarnMessage(warnMessage); + public void setWarnMessage(List warnMessages) { + myPreviewPanel.setWarnMessages(warnMessages); } public void setImage(@Nullable BufferedImage image, @NotNull String fileName) { @@ -682,13 +682,13 @@ class AndroidLayoutPreviewToolWindowForm implements Disposable { } public void updateDevicesAndTargets(@Nullable AndroidPlatform platform) { - final AndroidSdk sdkObject = platform != null ? platform.getSdk() : null; + final AndroidSdkData sdkData = platform != null ? platform.getSdkData() : null; final LayoutDevice selectedDevice = getSelectedDevice(); final String selectedDeviceName = selectedDevice != null ? selectedDevice.getName() : null; final List devices; - if (sdkObject != null) { - myLayoutDeviceManager.loadDevices(sdkObject); + if (sdkData != null) { + myLayoutDeviceManager.loadDevices(sdkData); devices = myLayoutDeviceManager.getCombinedList(); } else { @@ -720,9 +720,9 @@ class AndroidLayoutPreviewToolWindowForm implements Disposable { IAndroidTarget newSelectedTarget = null; final List targets; - if (sdkObject != null) { + if (sdkData != null) { targets = new ArrayList(); - for (IAndroidTarget target : sdkObject.getTargets()) { + for (IAndroidTarget target : sdkData.getTargets()) { if (target.isPlatform()) { if (target.hashString().equals(selectedTargetHashString)) { newSelectedTarget = target; @@ -752,7 +752,7 @@ class AndroidLayoutPreviewToolWindowForm implements Disposable { } if (modulePlatformHash != null) { - targetFromModule = sdkObject.findTargetByHashString(modulePlatformHash); + targetFromModule = sdkData.findTargetByHashString(modulePlatformHash); if (targetFromModule != null && targets.indexOf(targetFromModule) >= 0) { newSelectedTarget = targetFromModule; } @@ -917,7 +917,7 @@ class AndroidLayoutPreviewToolWindowForm implements Disposable { if (target == null) { target = androidPlatform.getTarget(); } - targetData = androidPlatform.getSdk().getTargetData(target); + targetData = androidPlatform.getSdkData().getTargetData(target); } if (targetData == null || targetData.areThemesCached()) { diff --git a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java index d2d5c9791214..149829c9fb2c 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java @@ -66,6 +66,8 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -316,8 +318,8 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { } BufferedImage image = null; - RenderingErrorMessage errorMessage = null; - String warnMessage = null; + FixableIssueMessage errorMessage = null; + final List warnMessages = new ArrayList(); final String imgPath = FileUtil.getTempDirectory() + "/androidLayoutPreview.png"; @@ -358,14 +360,15 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { final VirtualFile layoutXmlFile = psiFile.getVirtualFile(); synchronized (RENDERING_LOCK) { - final StringBuilder warnBuilder = new StringBuilder(); + if (target != null && theme != null) { + final RenderingResult result = + RenderUtil.renderLayout(facet.getModule(), layoutXmlText, layoutXmlFile, imgPath, target, facet, config, xdpi, ydpi, theme); - if (target != null && theme != null && - RenderUtil.renderLayout(myProject, layoutXmlText, layoutXmlFile, imgPath, - target, facet, config, xdpi, ydpi, theme, warnBuilder)) { - warnMessage = warnBuilder.toString(); + if (result != null) { + warnMessages.addAll(result.getWarnMessages()); final File input = new File(imgPath); image = ImageIO.read(input); + } } } } @@ -374,23 +377,23 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { String message = e.getPresentableMessage(); message = message != null ? message : AndroidBundle.message("android.layout.preview.default.error.message"); final Throwable[] causes = e.getCauses(); - errorMessage = causes.length > 0 ? new RenderingErrorMessage(message + ' ', "Details", "", new Runnable() { + errorMessage = causes.length > 0 ? new FixableIssueMessage(message + ' ', "Details", "", new Runnable() { @Override public void run() { showStackStace(causes); } - }) : new RenderingErrorMessage(message); + }) : new FixableIssueMessage(message); } catch (IOException e) { LOG.info(e); final String message = e.getMessage(); - errorMessage = new RenderingErrorMessage("I/O error" + (message != null ? ": " + message : "")); + errorMessage = new FixableIssueMessage("I/O error" + (message != null ? ": " + message : "")); } catch (AndroidSdkNotConfiguredException e) { LOG.debug(e); if (!AndroidMavenUtil.isMavenizedModule(facet.getModule())) { - errorMessage = new RenderingErrorMessage("Please ", "configure", " Android SDK", new Runnable() { + errorMessage = new FixableIssueMessage("Please ", "configure", " Android SDK", new Runnable() { @Override public void run() { AndroidSdkUtils.openModuleDependenciesConfigurable(facet.getModule()); @@ -398,13 +401,12 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { }); } else { - errorMessage = new RenderingErrorMessage(AndroidBundle.message("android.maven.cannot.parse.android.sdk.error", + errorMessage = new FixableIssueMessage(AndroidBundle.message("android.maven.cannot.parse.android.sdk.error", facet.getModule().getName())); } } - final RenderingErrorMessage finalErrorMessage = errorMessage; - final String finalWarnMessage = warnMessage; + final FixableIssueMessage finalErrorMessage = errorMessage; final BufferedImage finalImage = image; if (!myRenderingQueue.isEmpty()) { @@ -419,7 +421,7 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { return; } myToolWindowForm.setErrorMessage(finalErrorMessage); - myToolWindowForm.setWarnMessage(finalWarnMessage); + myToolWindowForm.setWarnMessage(warnMessages); if (finalErrorMessage == null) { myToolWindowForm.setImage(finalImage, fileName); } diff --git a/plugins/android/src/org/jetbrains/android/uipreview/FixableIssueMessage.java b/plugins/android/src/org/jetbrains/android/uipreview/FixableIssueMessage.java new file mode 100644 index 000000000000..ca42cf49e658 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/uipreview/FixableIssueMessage.java @@ -0,0 +1,42 @@ +package org.jetbrains.android.uipreview; + +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; + +/** +* @author Eugene.Kudelevsky +*/ +class FixableIssueMessage { + final String myBeforeLinkText; + final String myLinkText; + final String myAfterLinkText; + final Runnable myQuickFix; + final Collection> myAdditionalFixes; + + FixableIssueMessage(@NotNull String beforeLinkText, + @NotNull String linkText, + @NotNull String afterLinkText, + @Nullable Runnable quickFix) { + myBeforeLinkText = beforeLinkText; + myLinkText = linkText; + myAfterLinkText = afterLinkText; + myQuickFix = quickFix; + myAdditionalFixes = Collections.emptyList(); + } + + FixableIssueMessage(@NotNull String message) { + this(message, "", "", null); + } + + FixableIssueMessage(@NotNull String message, @NotNull Collection> quickFixes) { + myBeforeLinkText = message; + myLinkText = ""; + myAfterLinkText = ""; + myQuickFix = null; + myAdditionalFixes = quickFixes; + } +} diff --git a/plugins/android/src/org/jetbrains/android/uipreview/IncompatibleClassFileFormatException.java b/plugins/android/src/org/jetbrains/android/uipreview/IncompatibleClassFileFormatException.java index da67bb23c6b4..9fb3df3609ec 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/IncompatibleClassFileFormatException.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/IncompatibleClassFileFormatException.java @@ -1,7 +1,19 @@ package org.jetbrains.android.uipreview; +import org.jetbrains.annotations.NotNull; + /** * @author Eugene.Kudelevsky */ -public class IncompatibleClassFileFormatException extends Exception { +public class IncompatibleClassFileFormatException extends RuntimeException { + private final String myClassName; + + public IncompatibleClassFileFormatException(@NotNull String className) { + myClassName = className; + } + + @NotNull + public String getClassName() { + return myClassName; + } } diff --git a/plugins/android/src/org/jetbrains/android/uipreview/LayoutDeviceManager.java b/plugins/android/src/org/jetbrains/android/uipreview/LayoutDeviceManager.java index 3b29fa1024d0..18a485a6ba24 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/LayoutDeviceManager.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/LayoutDeviceManager.java @@ -6,7 +6,7 @@ import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; import com.intellij.openapi.diagnostic.Logger; -import org.jetbrains.android.sdk.AndroidSdk; +import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.w3c.dom.Document; @@ -149,13 +149,13 @@ public class LayoutDeviceManager { } } - public void loadDevices(@NotNull AndroidSdk sdk) { - loadDefaultAndUserDevices(sdk); - loadAddOnLayoutDevices(sdk); + public void loadDevices(@NotNull AndroidSdkData sdkData) { + loadDefaultAndUserDevices(sdkData); + loadAddOnLayoutDevices(sdkData); } - private void loadDefaultAndUserDevices(@NotNull AndroidSdk sdk) { - loadDefaultLayoutDevices(sdk.getLocation()); + private void loadDefaultAndUserDevices(@NotNull AndroidSdkData sdkData) { + loadDefaultLayoutDevices(sdkData.getLocation()); try { myUserLayoutDevices.clear(); @@ -181,8 +181,8 @@ public class LayoutDeviceManager { combineLayoutDevices(); } - private void loadAddOnLayoutDevices(@NotNull AndroidSdk sdk) { - for (IAndroidTarget target : sdk.getTargets()) { + private void loadAddOnLayoutDevices(@NotNull AndroidSdkData sdkData) { + for (IAndroidTarget target : sdkData.getTargets()) { if (!target.isPlatform()) { File deviceXml = new File(target.getLocation(), SdkConstants.FN_DEVICES_XML); if (deviceXml.isFile()) { diff --git a/plugins/android/src/org/jetbrains/android/uipreview/ProjectCallback.java b/plugins/android/src/org/jetbrains/android/uipreview/ProjectCallback.java index 6d7fed659850..230e01821dc2 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/ProjectCallback.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/ProjectCallback.java @@ -23,14 +23,11 @@ import com.android.ide.common.resources.IntArrayWrapper; import com.android.resources.ResourceType; import com.android.sdklib.SdkConstants; import com.android.util.Pair; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; -import com.intellij.openapi.util.Computable; +import com.intellij.util.containers.HashSet; import gnu.trove.TIntObjectHashMap; import gnu.trove.TObjectIntHashMap; -import org.jetbrains.android.dom.manifest.Manifest; -import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,6 +47,7 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { private final Set myMissingClasses = new TreeSet(); private final Map myBrokenClasses = new HashMap(); + private final Set myClassesWithIncorrectFormat = new HashSet(); private final Map> myLoadedClasses = new HashMap>(); @@ -113,9 +111,9 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { return createNewInstance(aClass, constructorSignature, constructorArgs); } - aClass = loadClass(className); - try { + aClass = loadClass(className); + if (aClass != null) { final Object viewObject = createNewInstance(aClass, constructorSignature, constructorArgs); myLoadedClasses.put(className, aClass); @@ -128,7 +126,14 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { } catch (InvocationTargetException e) { LOG.info(e); - myBrokenClasses.put(className, e.getCause()); + + final Throwable cause = e.getCause(); + if (cause instanceof IncompatibleClassFileFormatException) { + myClassesWithIncorrectFormat.add(((IncompatibleClassFileFormatException)cause).getClassName()); + } + else { + myBrokenClasses.put(className, cause); + } } catch (IllegalAccessException e) { LOG.info(e); @@ -142,6 +147,9 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { LOG.info(e); myBrokenClasses.put(className, e.getCause()); } + catch (IncompatibleClassFileFormatException e) { + myClassesWithIncorrectFormat.add(e.getClassName()); + } try { return createMockView(className, constructorSignature, constructorArgs); @@ -167,7 +175,7 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { } @Nullable - private Class loadClass(String className) { + private Class loadClass(String className) throws IncompatibleClassFileFormatException { try { if (myProjectClassLoader == null) { myProjectClassLoader = new ProjectClassLoader(myParentClassLoader, myModule); @@ -181,11 +189,10 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { } return null; } - catch (UnsupportedClassVersionError e) { - LOG.info(e); - myBrokenClasses.put(className, e); - return null; - } + } + + public boolean hasUnsupportedClassVersionProblem() { + return myClassesWithIncorrectFormat.size() > 0; } private Object createMockView(String className, Class[] constructorSignature, Object[] constructorArgs) @@ -221,6 +228,16 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { return viewObject; } + @NotNull + public Set getClassesWithIncorrectFormat() { + return myClassesWithIncorrectFormat; + } + + @NotNull + public Module getModule() { + return myModule; + } + private static String getShortClassName(String fqcn) { if (fqcn.startsWith("android.")) { // android.foo.Name -> android...Name @@ -337,27 +354,21 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { } public void loadAndParseRClass() throws ClassNotFoundException, IncompatibleClassFileFormatException { - final String className = ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - @Override - public String compute() { - return getRClassName(myModule); - } - }); - if (className == null) { + final String rClassName = RenderUtil.getRClassName(myModule); + + if (rClassName == null) { LOG.info("loadAndParseRClass: failed to find manifest package for project %1$s"); return; } + loadAndParseRClass(rClassName); + } + public void loadAndParseRClass(@NotNull String className) throws ClassNotFoundException, IncompatibleClassFileFormatException { Class aClass = myLoadedClasses.get(className); if (aClass == null) { ProjectClassLoader loader = new ProjectClassLoader(null, myModule); - try { - aClass = loader.loadClass(className); - } - catch (UnsupportedClassVersionError e) { - throw new IncompatibleClassFileFormatException(); - } + aClass = loader.loadClass(className); + if (aClass != null) { myLoadedClasses.put(className, aClass); } @@ -414,20 +425,4 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback { return true; } - - @Nullable - private static String getRClassName(Module module) { - final AndroidFacet facet = AndroidFacet.getInstance(module); - if (facet == null) { - return null; - } - - final Manifest manifest = facet.getManifest(); - if (manifest == null) { - return null; - } - - final String aPackage = manifest.getPackage().getValue(); - return aPackage == null ? null : aPackage + ".R"; - } } diff --git a/plugins/android/src/org/jetbrains/android/uipreview/ProjectClassLoader.java b/plugins/android/src/org/jetbrains/android/uipreview/ProjectClassLoader.java index 8a82aeaca1d2..9e4391d91e55 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/ProjectClassLoader.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/ProjectClassLoader.java @@ -5,6 +5,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.CompilerModuleExtension; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.HashSet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.annotations.Nullable; @@ -17,6 +18,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @author Eugene.Kudelevsky @@ -39,7 +41,26 @@ public final class ProjectClassLoader extends ClassLoader { throw new ClassNotFoundException(name); } - Class aClass = loadClassFromModule(myModule, name); + try { + final Class aClass = loadClassFromModuleOrDependency(myModule, name, new HashSet()); + if (aClass != null) { + return aClass; + } + } + catch (UnsupportedClassVersionError e) { + throw new IncompatibleClassFileFormatException(name); + } + + throw new ClassNotFoundException(name); + } + + @Nullable + private Class loadClassFromModuleOrDependency(Module module, String name, Set visited) { + if (!visited.add(module)) { + return null; + } + + Class aClass = loadClassFromModule(module, name); if (aClass != null) { return aClass; } @@ -49,14 +70,13 @@ public final class ProjectClassLoader extends ClassLoader { return aClass; } - for (Module depModule : ModuleRootManager.getInstance(myModule).getDependencies(false)) { - aClass = loadClassFromModule(depModule, name); + for (Module depModule : ModuleRootManager.getInstance(module).getDependencies(false)) { + aClass = loadClassFromModuleOrDependency(depModule, name, visited); if (aClass != null) { return aClass; } } - - throw new ClassNotFoundException(name); + return null; } @Nullable diff --git a/plugins/android/src/org/jetbrains/android/uipreview/RenderUtil.java b/plugins/android/src/org/jetbrains/android/uipreview/RenderUtil.java index 5d7d57eab54e..973be7a65872 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/RenderUtil.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/RenderUtil.java @@ -3,22 +3,41 @@ package org.jetbrains.android.uipreview; import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; -import com.android.ide.common.resources.*; +import com.android.ide.common.resources.ResourceDeltaKind; +import com.android.ide.common.resources.ResourceFolder; +import com.android.ide.common.resources.ResourceRepository; +import com.android.ide.common.resources.ScanningContext; import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.ide.common.resources.configuration.VersionQualifier; -import com.android.io.*; +import com.android.io.IAbstractFile; +import com.android.io.IAbstractFolder; +import com.android.io.IAbstractResource; +import com.android.io.StreamException; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; +import com.intellij.compiler.impl.javaCompiler.javac.JavacSettings; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ui.configuration.ClasspathEditor; +import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; +import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.xml.XmlTag; +import com.intellij.util.containers.HashSet; import org.jetbrains.android.dom.manifest.Application; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.facet.AndroidFacet; @@ -73,7 +92,7 @@ public class RenderUtil { config.setVersionQualifier(new VersionQualifier(target.getVersion().getApiLevel())); - final RenderServiceFactory factory = platform.getSdk().getTargetData(target).getRenderServiceFactory(project); + final RenderServiceFactory factory = platform.getSdkData().getTargetData(target).getRenderServiceFactory(project); if (factory == null) { throw new RenderingException(AndroidBundle.message("android.layout.preview.cannot.load.library.error")); } @@ -81,7 +100,7 @@ public class RenderUtil { final ProjectResources projectResources = new ProjectResources(); final VirtualFile[] resourceDirs = facet.getLocalResourceManager().getAllResourceDirs(); - final IAbstractFolder[] resFolders = toAbstractFolders(project, resourceDirs); + final IAbstractFolder[] resFolders = toAbstractFolders(resourceDirs); loadResources(projectResources, layoutXmlText, layoutXmlFile, resFolders); final int minSdkVersion = getMinSdkVersion(facet); @@ -109,18 +128,20 @@ public class RenderUtil { } } - public static boolean renderLayout(@NotNull Project project, - @NotNull String layoutXmlText, - @Nullable VirtualFile layoutXmlFile, - @NotNull String imgPath, - @NotNull IAndroidTarget target, - @NotNull AndroidFacet facet, - @NotNull FolderConfiguration config, - float xdpi, - float ydpi, - @NotNull ThemeData theme, - StringBuilder warningBuilder) + @Nullable + public static RenderingResult renderLayout(@NotNull final Module module, + @NotNull String layoutXmlText, + @Nullable VirtualFile layoutXmlFile, + @NotNull String imgPath, + @NotNull IAndroidTarget target, + @NotNull AndroidFacet facet, + @NotNull FolderConfiguration config, + float xdpi, + float ydpi, + @NotNull ThemeData theme) throws RenderingException, IOException, AndroidSdkNotConfiguredException { + final Project project = module.getProject(); + final Sdk sdk = ModuleRootManager.getInstance(facet.getModule()).getSdk(); if (sdk == null || !(sdk.getSdkType() instanceof AndroidSdkType)) { throw new AndroidSdkNotConfiguredException(); @@ -138,7 +159,7 @@ public class RenderUtil { config.setVersionQualifier(new VersionQualifier(target.getVersion().getApiLevel())); - final RenderServiceFactory factory = platform.getSdk().getTargetData(target).getRenderServiceFactory(project); + final RenderServiceFactory factory = platform.getSdkData().getTargetData(target).getRenderServiceFactory(project); if (factory == null) { throw new RenderingException(AndroidBundle.message("android.layout.preview.cannot.load.library.error")); } @@ -146,14 +167,17 @@ public class RenderUtil { final ProjectResources projectResources = new ProjectResources(); final VirtualFile[] resourceDirs = facet.getLocalResourceManager().getAllResourceDirs(); - final IAbstractFolder[] resFolders = toAbstractFolders(project, resourceDirs); + final IAbstractFolder[] resFolders = toAbstractFolders(resourceDirs); loadResources(projectResources, layoutXmlText, layoutXmlFile, resFolders); final int minSdkVersion = getMinSdkVersion(facet); String missingRClassMessage = null; boolean missingRClass = false; + boolean incorrectRClassFormat = false; + String rClassName = null; final ProjectCallback callback = new ProjectCallback(factory.getLibrary(), facet.getModule(), projectResources); + try { callback.loadAndParseRClass(); } @@ -164,8 +188,8 @@ public class RenderUtil { } catch (IncompatibleClassFileFormatException e) { LOG.debug(e); - missingRClassMessage = "Incompatible R.class file format"; - missingRClass = true; + incorrectRClassFormat = true; + rClassName = e.getClassName(); } final RenderResources resolver = @@ -180,52 +204,34 @@ public class RenderUtil { throw new RenderingException(e); } if (session == null) { - return false; + return null; + } + + final List warnMessages = new ArrayList(); + + if (callback.hasUnsupportedClassVersionProblem() || (incorrectRClassFormat && callback.hasLoadedClasses())) { + reportIncorrectClassFormatWarning(callback, rClassName, incorrectRClassFormat, warnMessages); } if (missingRClass && callback.hasLoadedClasses()) { - warningBuilder.append(missingRClassMessage != null && missingRClassMessage.length() > 0 - ? ("Class not found error: " + missingRClassMessage + ".") - : "R class not found.") - .append(" Try to build project\n"); + final StringBuilder builder = new StringBuilder(); + builder.append(missingRClassMessage != null && missingRClassMessage.length() > 0 + ? ("Class not found error: " + missingRClassMessage + ".") + : "R class not found.") + .append(" Try to build project"); + warnMessages.add(new FixableIssueMessage(builder.toString())); } - final Set missingClasses = callback.getMissingClasses(); - if (missingClasses.size() > 0) { - if (missingClasses.size() > 1) { - warningBuilder.append("Missing classes:\n"); - for (String missingClass : missingClasses) { - warningBuilder.append("       ").append(missingClass).append('\n'); - } - } - else { - warningBuilder.append("Missing class ").append(missingClasses.iterator().next()).append('\n'); - } - } + reportMissingClassesWarning(warnMessages, callback.getMissingClasses()); - final Map brokenClasses = callback.getBrokenClasses(); - if (brokenClasses.size() > 0) { - if (brokenClasses.size() > 1) { - warningBuilder.append("Unable to initialize:\n"); - for (String brokenClass : brokenClasses.keySet()) { - warningBuilder.append(" ").append(brokenClass).append('\n'); - } - } - else { - warningBuilder.append("Unable to initialize ").append(brokenClasses.keySet().iterator().next()); - } - } - - if (warningBuilder.length() > 0 && warningBuilder.charAt(warningBuilder.length() - 1) == '\n') { - warningBuilder.deleteCharAt(warningBuilder.length() - 1); - } + reportBrokenClassesWarning(warnMessages, callback.getBrokenClasses()); final Result result = session.getResult(); if (!result.isSuccess()) { final Throwable exception = result.getException(); if (exception != null) { - final List exceptionsFromWarnings = getNonNullValues(brokenClasses); + final List exceptionsFromWarnings = getNonNullValues(callback.getBrokenClasses()); if (exceptionsFromWarnings.size() > 0 && exception instanceof ClassCastException && @@ -240,13 +246,215 @@ public class RenderUtil { LOG.info(message); throw new RenderingException(); } - return false; + return null; } final String format = FileUtil.getExtension(imgPath); ImageIO.write(session.getImage(), format, new File(imgPath)); - return true; + return new RenderingResult(warnMessages); + } + + private static void reportBrokenClassesWarning(@NotNull List warnMessages, + @NotNull Map brokenClasses) { + if (brokenClasses.size() > 0) { + final StringBuilder builder = new StringBuilder(); + if (brokenClasses.size() > 1) { + builder.append("Unable to initialize:\n"); + for (String brokenClass : brokenClasses.keySet()) { + builder.append(" ").append(brokenClass).append('\n'); + } + } + else { + builder.append("Unable to initialize ").append(brokenClasses.keySet().iterator().next()); + } + removeLastNewLineChar(builder); + warnMessages.add(new FixableIssueMessage(builder.toString())); + } + } + + private static void reportMissingClassesWarning(@NotNull List warnMessages, + @NotNull Set missingClasses) { + if (missingClasses.size() > 0) { + final StringBuilder builder = new StringBuilder(); + if (missingClasses.size() > 1) { + builder.append("Missing classes:\n"); + for (String missingClass : missingClasses) { + builder.append("       ").append(missingClass).append('\n'); + } + } + else { + builder.append("Missing class ").append(missingClasses.iterator().next()); + } + removeLastNewLineChar(builder); + warnMessages.add(new FixableIssueMessage(builder.toString())); + } + } + + private static void reportIncorrectClassFormatWarning(@NotNull ProjectCallback callback, + @Nullable String rClassName, + boolean incorrectRClassFormat, + @NotNull List warnMessages) { + final Module module = callback.getModule(); + final Project project = module.getProject(); + final List problemModules = getProblemModules(module); + final StringBuilder builder = new StringBuilder("Preview can be incorrect: unsupported classes version"); + final List> quickFixes = new ArrayList>(); + + if (problemModules.size() > 0) { + quickFixes.add(new Pair("Rebuild project with '-target 1.6'", new Runnable() { + @Override + public void run() { + final JavacSettings settings = JavacSettings.getInstance(project); + if (settings.ADDITIONAL_OPTIONS_STRING.length() > 0) { + settings.ADDITIONAL_OPTIONS_STRING += ' '; + } + settings.ADDITIONAL_OPTIONS_STRING += "-target 1.6"; + CompilerManager.getInstance(project).rebuild(null); + } + })); + + quickFixes.add(new Pair("Change Java SDK to 1.5/1.6", new Runnable() { + @Override + public void run() { + final Set sdkNames = getSdkNamesFromModules(problemModules); + + if (sdkNames.size() == 1) { + final Sdk sdk = ProjectJdkTable.getInstance().findJdk(sdkNames.iterator().next()); + + if (sdk != null && sdk.getSdkType() instanceof AndroidSdkType) { + final ProjectStructureConfigurable config = ProjectStructureConfigurable.getInstance(project); + + if (ShowSettingsUtil.getInstance().editConfigurable(project, config, new Runnable() { + public void run() { + config.select(sdk, true); + } + })) { + askAndRebuild(project); + } + return; + } + } + + final String moduleToSelect = problemModules.size() > 0 + ? problemModules.iterator().next().getName() + : null; + if (ModulesConfigurator.showDialog(project, moduleToSelect, ClasspathEditor.NAME)) { + askAndRebuild(project); + } + } + })); + + final Set classesWithIncorrectFormat = new HashSet(callback.getClassesWithIncorrectFormat()); + if (incorrectRClassFormat && rClassName != null) { + classesWithIncorrectFormat.add(rClassName); + } + if (classesWithIncorrectFormat.size() > 0) { + quickFixes.add(new Pair("Details", new Runnable() { + @Override + public void run() { + showClassesWithIncorrectFormat(project, classesWithIncorrectFormat); + } + })); + } + + builder.append("\nFollowing modules are built with incompatible JDK: "); + + for (Iterator it = problemModules.iterator(); it.hasNext(); ) { + Module problemModule = it.next(); + builder.append(problemModule.getName()); + if (it.hasNext()) { + builder.append(", "); + } + } + } + + warnMessages.add(new FixableIssueMessage(builder.toString(), quickFixes)); + } + + private static void showClassesWithIncorrectFormat(@NotNull Project project, @NotNull Set classesWithIncorrectFormat) { + final StringBuilder builder = new StringBuilder("Classes with incompatible format:\n"); + + for (Iterator it = classesWithIncorrectFormat.iterator(); it.hasNext(); ) { + builder.append(" ").append(it.next()); + + if (it.hasNext()) { + builder.append('\n'); + } + } + Messages.showInfoMessage(project, builder.toString(), "Unsupported class version"); + } + + private static void askAndRebuild(Project project) { + final int r = + Messages.showYesNoDialog(project, "You have to rebuild project to see fixed preview. Would you like to do it?", + "Rebuild project", Messages.getQuestionIcon()); + if (r == Messages.YES) { + CompilerManager.getInstance(project).rebuild(null); + } + } + + @NotNull + private static Set getSdkNamesFromModules(@NotNull Collection modules) { + final Set result = new HashSet(); + + for (Module module : modules) { + final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); + + if (sdk != null) { + result.add(sdk.getName()); + } + } + return result; + } + + @NotNull + private static List getProblemModules(@NotNull Module root) { + final List result = new ArrayList(); + collectProblemModules(root, new HashSet(), result); + return result; + } + + private static void collectProblemModules(@NotNull Module module, @NotNull Set visited, @NotNull Collection result) { + if (!visited.add(module)) { + return; + } + + if (isBuiltByJdk7OrHigher(module)) { + result.add(module); + } + + for (Module depModule : ModuleRootManager.getInstance(module).getDependencies(false)) { + collectProblemModules(depModule, visited, result); + } + } + + private static boolean isBuiltByJdk7OrHigher(@NotNull Module module) { + Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); + + if (sdk == null) { + return false; + } + + if (sdk.getSdkType() instanceof AndroidSdkType) { + final AndroidSdkAdditionalData data = (AndroidSdkAdditionalData)sdk.getSdkAdditionalData(); + + if (data != null) { + final Sdk jdk = data.getJavaSdk(); + + if (jdk != null) { + sdk = jdk; + } + } + } + return sdk.getSdkType() instanceof JavaSdk && + JavaSdk.getInstance().isOfVersionOrHigher(sdk, JavaSdkVersion.JDK_1_7); + } + + private static void removeLastNewLineChar(StringBuilder builder) { + if (builder.length() > 0 && builder.charAt(builder.length() - 1) == '\n') { + builder.deleteCharAt(builder.length() - 1); + } } @NotNull @@ -283,6 +491,7 @@ public class RenderUtil { private static int getMinSdkVersion(final AndroidFacet facet) { final XmlTag manifestTag = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable @Override public XmlTag compute() { final Manifest manifest = facet.getManifest(); @@ -301,7 +510,7 @@ public class RenderUtil { } @NotNull - private static IAbstractFolder[] toAbstractFolders(@NotNull Project project, @NotNull VirtualFile[] folders) { + private static IAbstractFolder[] toAbstractFolders(@NotNull VirtualFile[] folders) { final IAbstractFolder[] result = new IAbstractFolder[folders.length]; for (int i = 0; i < folders.length; i++) { @@ -329,15 +538,15 @@ public class RenderUtil { if (resFolder != null) { for (final IAbstractResource childRes : folder.listMembers()) { - + if (childRes instanceof IAbstractFile) { final VirtualFile vFile; - if (childRes instanceof BufferingFileWrapper) { + if (childRes instanceof BufferingFileWrapper) { final BufferingFileWrapper fileWrapper = (BufferingFileWrapper)childRes; final String filePath = FileUtil.toSystemIndependentName(fileWrapper.getOsLocation()); vFile = LocalFileSystem.getInstance().findFileByPath(filePath); - + if (vFile != null && vFile == layoutXmlFile && layoutXmlFileText != null) { resFolder.processFile(new MyFileWrapper(layoutXmlFileText, childRes), ResourceDeltaKind.ADDED, scanningContext); } @@ -372,6 +581,28 @@ public class RenderUtil { return result.toString(); } + @Nullable + public static String getRClassName(@NotNull final Module module) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public String compute() { + final AndroidFacet facet = AndroidFacet.getInstance(module); + if (facet == null) { + return null; + } + + final Manifest manifest = facet.getManifest(); + if (manifest == null) { + return null; + } + + final String aPackage = manifest.getPackage().getValue(); + return aPackage == null ? null : aPackage + ".R"; + } + }); + } + private static class MyFileWrapper implements IAbstractFile { private final String myLayoutXmlFileText; private final IAbstractResource myChildRes; diff --git a/plugins/android/src/org/jetbrains/android/uipreview/RenderingErrorMessage.java b/plugins/android/src/org/jetbrains/android/uipreview/RenderingErrorMessage.java deleted file mode 100644 index 3cbf3211631a..000000000000 --- a/plugins/android/src/org/jetbrains/android/uipreview/RenderingErrorMessage.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.jetbrains.android.uipreview; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** -* @author Eugene.Kudelevsky -*/ -class RenderingErrorMessage { - final String myBeforeLinkText; - final String myLinkText; - final String myAfterLinkText; - final Runnable myQuickFix; - - RenderingErrorMessage(@NotNull String beforeLinkText, - @NotNull String linkText, - @NotNull String afterLinkText, - @Nullable Runnable quickFix) { - myBeforeLinkText = beforeLinkText; - myLinkText = linkText; - myAfterLinkText = afterLinkText; - myQuickFix = quickFix; - } - - RenderingErrorMessage(@NotNull String message) { - this(message, "", "", null); - } -} diff --git a/plugins/android/src/org/jetbrains/android/uipreview/RenderingResult.java b/plugins/android/src/org/jetbrains/android/uipreview/RenderingResult.java new file mode 100644 index 000000000000..017ede25755d --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/uipreview/RenderingResult.java @@ -0,0 +1,21 @@ +package org.jetbrains.android.uipreview; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class RenderingResult { + private final List myWarnMessages; + + public RenderingResult(@NotNull List warnMessages) { + myWarnMessages = warnMessages; + } + + @NotNull + public List getWarnMessages() { + return myWarnMessages; + } +} diff --git a/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java b/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java index 966daab2e5cd..4b8c18581928 100644 --- a/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java +++ b/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java @@ -36,7 +36,7 @@ import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; import com.intellij.util.PathUtil; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidFacetConfiguration; -import org.jetbrains.android.sdk.AndroidSdk; +import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.android.sdk.AndroidSdkAdditionalData; import org.jetbrains.android.sdk.AndroidSdkType; import org.jetbrains.android.sdk.EmptySdkLog; @@ -156,8 +156,8 @@ public abstract class AndroidTestCase extends JavaCodeInsightFixtureTestCase { sdkModificator.addRoot(resFolder, OrderRootType.CLASSES); AndroidSdkAdditionalData data = new AndroidSdkAdditionalData(sdk); - AndroidSdk sdkObject = AndroidSdk.parse(sdkPath, new EmptySdkLog()); - data.setBuildTarget(sdkObject.findTargetByName("Android 1.5")); + AndroidSdkData sdkData = AndroidSdkData.parse(sdkPath, new EmptySdkLog()); + data.setBuildTarget(sdkData.findTargetByName("Android 1.5")); sdkModificator.setSdkAdditionalData(data); sdkModificator.commitChanges(); return sdk; diff --git a/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntImportsIndex.java b/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntImportsIndex.java index 93a589fdb31f..a420ffa588ee 100644 --- a/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntImportsIndex.java +++ b/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntImportsIndex.java @@ -96,7 +96,7 @@ public class AntImportsIndex extends ScalarIndexExtension{ } public KeyDescriptor getKeyDescriptor() { - return new EnumeratorIntegerDescriptor(); + return EnumeratorIntegerDescriptor.INSTANCE; } public FileBasedIndex.InputFilter getInputFilter() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/secondUnsafeCall/SecondUnsafeCallInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/secondUnsafeCall/SecondUnsafeCallInspection.java index cd7b116e5393..e541f2455d95 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/secondUnsafeCall/SecondUnsafeCallInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/secondUnsafeCall/SecondUnsafeCallInspection.java @@ -18,14 +18,14 @@ package org.jetbrains.plugins.groovy.codeInspection.secondUnsafeCall; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.annotator.inspections.SecondUnsafeCallQuickFix; import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; import org.jetbrains.plugins.groovy.codeInspection.GroovySuppressableInspectionTool; -import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -46,32 +46,33 @@ public class SecondUnsafeCallInspection extends GroovySuppressableInspectionTool }); } - private void checkForSecondUnsafeCall(GrExpression expression, ProblemsHolder holder) { + private static void checkForSecondUnsafeCall(GrExpression expression, ProblemsHolder holder) { checkForSecondUnsafeCall(expression, holder, null); } - private void checkForSecondUnsafeCall(GrExpression expression, ProblemsHolder holder, PsiElement hightlightElement) { - if (hightlightElement == null) hightlightElement = expression; + private static void checkForSecondUnsafeCall(GrExpression expression, ProblemsHolder holder, @Nullable PsiElement highlightElement) { + if (highlightElement == null) highlightElement = expression; - final GrReferenceExpression referenceExpression = (GrReferenceExpression) expression; + final GrReferenceExpression referenceExpression = (GrReferenceExpression)expression; - if (GroovyElementTypes.mDOT.equals(referenceExpression.getDotTokenType())) { + if (GroovyTokenTypes.mDOT.equals(referenceExpression.getDotTokenType())) { // a?.b or a?.b() - final GrExpression qualifierExpression = referenceExpression.getQualifierExpression(); + final GrExpression qualifier = referenceExpression.getQualifierExpression(); // a?.b() - if (qualifierExpression instanceof GrMethodCallExpression) { - final GrExpression expression1 = ((GrMethodCallExpression) qualifierExpression).getInvokedExpression(); + if (qualifier instanceof GrMethodCallExpression) { + final GrExpression expression1 = ((GrMethodCallExpression)qualifier).getInvokedExpression(); // a?.b if (!(expression1 instanceof GrReferenceExpression)) return; - if (GroovyElementTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression) expression1).getDotTokenType())) { - holder.registerProblem(hightlightElement, GroovyInspectionBundle.message("call.can.throw.npe"), new SecondUnsafeCallQuickFix()); + if (GroovyTokenTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression)expression1).getDotTokenType())) { + holder.registerProblem(highlightElement, GroovyInspectionBundle.message("call.can.throw.npe"), new SecondUnsafeCallQuickFix()); } - } else + } + else // a?.b - if (qualifierExpression instanceof GrReferenceExpression) { - if (GroovyElementTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression) qualifierExpression).getDotTokenType())) { - holder.registerProblem(hightlightElement, GroovyInspectionBundle.message("call.can.throw.npe"), new SecondUnsafeCallQuickFix()); + if (qualifier instanceof GrReferenceExpression) { + if (GroovyTokenTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression)qualifier).getDotTokenType())) { + holder.registerProblem(highlightElement, GroovyInspectionBundle.message("call.can.throw.npe"), new SecondUnsafeCallQuickFix()); } } } @@ -104,185 +105,4 @@ public class SecondUnsafeCallInspection extends GroovySuppressableInspectionTool public boolean isEnabledByDefault() { return true; } - - private IElementType getDotType(PsiElement element) { - if (element instanceof GrReferenceExpression) return ((GrReferenceExpression) element).getDotTokenType(); - else if (element instanceof GrMethodCallExpression) { - final GrExpression invokedExpr = ((GrMethodCallExpression) element).getInvokedExpression(); - - if (invokedExpr instanceof GrReferenceExpression) return ((GrReferenceExpression) element).getDotTokenType(); - } - - return null; - } -} - - -///* -// * Copyright 2000-2007 JetBrains s.r.o. -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * http://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// */ -//package org.jetbrains.plugins.groovy.codeInspection.secondUnsafeCall; -// -//import org.jetbrains.annotations.Nls; -//import org.jetbrains.annotations.NonNls; -//import org.jetbrains.annotations.NotNull; -//import org.jetbrains.plugins.groovy.annotator.inspections.SecondUnsafeCallQuickFix; -//import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; -//import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; -//import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; -//import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; -//import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -//import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; -//import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; -// -///** -// * User: Dmitry.Krasilschikov -// * Date: 13.11.2007 -// */ -//public class SecondUnsafeCallInspection extends BaseInspection { -// //@NotNull -// //public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { -// // return new GroovyPsiElementVisitor(new GroovyElementVisitor() { -// // public void visitReferenceExpression(GrReferenceExpression refExpression) { -// // checkForSecondUnsafeCall(refExpression, holder); -// // } -// // }); -// //} -// -// //private void checkForSecondUnsafeCall(GrExpression expression, ProblemsHolder holder) { -// // checkForSecondUnsafeCall(expression, holder, null); -// //} -// // -// //private void checkForSecondUnsafeCall(GrExpression expression, ProblemsHolder holder, PsiElement hightlightElement) { -// // if (hightlightElement == null) hightlightElement = expression; -// // -// // final GrReferenceExpression referenceExpression = (GrReferenceExpression)expression; -// // -// // if (GroovyElementTypes.mDOT.equals(referenceExpression.getDotTokenType())) { -// // // a?.b or a?.b() -// // final GrExpression qualifierExpression = referenceExpression.getQualifierExpression(); -// // // a?.b() -// // if (qualifierExpression instanceof GrMethodCallExpression) { -// // final GrExpression expression1 = ((GrMethodCallExpression)qualifierExpression).getInvokedExpression(); -// // // a?.b -// // if (!(expression1 instanceof GrReferenceExpression)) return; -// // -// // if (GroovyElementTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression)expression1).getDotTokenType())) { -// // holder.registerProblem(hightlightElement, GroovyInspectionBundle.message("call.can.throw.npe"), new SecondUnsafeCallQuickFix()); -// // } -// // } -// // else -// // // a?.b -// // if (qualifierExpression instanceof GrReferenceExpression) { -// // if (GroovyElementTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression)qualifierExpression).getDotTokenType())) { -// // holder.registerProblem(hightlightElement, GroovyInspectionBundle.message("call.can.throw.npe"), new SecondUnsafeCallQuickFix()); -// // } -// // } -// // } -// //} -// -// @Nls -// @NotNull -// public String getGroupDisplayName() { -// return GroovyInspectionBundle.message("second.unsafe.call"); -// } -// -// @Nls -// @NotNull -// public String getDisplayName() { -// return GroovyInspectionBundle.message("second.unsafe.call"); -// } -// -// @NonNls -// @NotNull -// public String getShortName() { -// return "SecondUnsafeCall"; -// } -// -// protected BaseInspectionVisitor buildVisitor() { -// return new BaseInspectionVisitor() { -// public void visitReferenceExpression(GrReferenceExpression expression) { -// //if (hightlightElement == null) hightlightElement = expression; -// -// final GrReferenceExpression referenceExpression = (GrReferenceExpression)expression; -// -// if (GroovyElementTypes.mDOT.equals(referenceExpression.getDotTokenType())) { -// // a?.b or a?.b() -// final GrExpression qualifierExpression = referenceExpression.getQualifierExpression(); -// // a?.b() -// if (qualifierExpression instanceof GrMethodCallExpression) { -// final GrExpression expression1 = ((GrMethodCallExpression)qualifierExpression).getInvokedExpression(); -// // a?.b -// if (!(expression1 instanceof GrReferenceExpression)) return; -// -// if (GroovyElementTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression)expression1).getDotTokenType())) { -// registerError(expression, GroovyInspectionBundle.message("call.can.throw.npe")/*, new SecondUnsafeCallQuickFix()*/); -// } -// } -// else -// // a?.b -// if (qualifierExpression instanceof GrReferenceExpression) { -// if (GroovyElementTypes.mOPTIONAL_DOT.equals(((GrReferenceExpression)qualifierExpression).getDotTokenType())) { -// registerError(expression, GroovyInspectionBundle.message("call.can.throw.npe"), -// new SecondUnsafeCallQuickFix()); -// } -// } -// } -// } -// }; -// } -// -// //private static class Visitor extends BaseInspectionVisitor { -// // -// // public void visitReferenceExpression(GrReferenceExpression referenceExpression) { -// // super.visitReferenceExpression(referenceExpression); -// // -// // -// // -// // final GrExpression returnValue = referenceExpression.getReturnValue(); -// // if (returnValue != null) { -// // return; -// // } -// // final GrMethod method = -// // PsiTreeUtil.getParentOfType(referenceExpression, GrMethod.class); -// // if (method == null) { -// // return; -// // } -// // final GrOpenBlock body = method.getBlock(); -// // if (body == null) { -// // return; -// // } -// // if (ControlFlowUtils.openBlockCompletesWithStatement(body, referenceExpression)) { -// // registerStatementError(referenceExpression); -// // } -// // } -// //} -// -// public boolean isEnabledByDefault() { -// return true; -// } -// -// //private IElementType getDotType(PsiElement element) { -// // if (element instanceof GrReferenceExpression) { -// // return ((GrReferenceExpression)element).getDotTokenType(); -// // } -// // else if (element instanceof GrMethodCallExpression) { -// // final GrExpression invokedExpr = ((GrMethodCallExpression)element).getInvokedExpression(); -// // -// // if (invokedExpr instanceof GrReferenceExpression) return ((GrReferenceExpression)element).getDotTokenType(); -// // } -// // -// // return null; -// //} -//} +} \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyShellAction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyShellAction.java index 30f9c07b8119..9fb6e8c7d1ca 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyShellAction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyShellAction.java @@ -165,9 +165,10 @@ public class GroovyShellAction extends DumbAwareAction { DefaultGroovyScriptRunner.configureGenericGroovyRunner(javaParameters, module, "groovy.ui.GroovyMain", true); PathsList list = GroovyScriptRunner.getClassPathFromRootModel(module, true, javaParameters, true); if (list != null) { - javaParameters.getProgramParametersList().addAll("--classpath", list.getPathsString()); + javaParameters.getClassPath().addAll(list.getPathList()); } javaParameters.getProgramParametersList().addAll("-p", GroovyScriptRunner.getPathInConf("console.txt")); + //javaParameters.getVMParametersList().add("-Xdebug"); javaParameters.getVMParametersList().add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5239"); javaParameters.setWorkingDirectory(getWorkingDir()); final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index 964b3de73f30..2391408ef384 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -45,6 +45,7 @@ import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.ExceptionUtil; import com.intellij.util.PathUtil; +import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ConcurrentMultiMap; import com.intellij.util.containers.MultiMap; import com.intellij.util.indexing.*; @@ -256,9 +257,22 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { private static volatile List> ourStandardScripts; private static List> getStandardScripts() { - if (ourStandardScripts == null) { - synchronized (SCRIPTS_CACHE) { - if (ourStandardScripts == null) { + List> result = ourStandardScripts; + if (result != null) { + return result; + } + + final Semaphore semaphore = new Semaphore(); + semaphore.down(); + ourPool.execute(new Runnable() { + @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") + @Override + public void run() { + if (ourStandardScripts != null) { + return; + } + + try { Set scriptFolders = new LinkedHashSet(); // perhaps a separate extension for that? for (GroovyFrameworkConfigNotification extension : GroovyFrameworkConfigNotification.EP_NAME.getExtensions()) { @@ -285,11 +299,28 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } } } - } ourStandardScripts = executors; } + catch (OutOfMemoryError e) { + stopGdsl = true; + throw e; + } + catch (NoClassDefFoundError e) { + stopGdsl = true; + throw e; + } + finally { + semaphore.up(); + } } + }); + + while (ourStandardScripts == null && !stopGdsl && !semaphore.waitFor(20)) { + ProgressManager.checkCanceled(); + } + if (stopGdsl) { + return Collections.emptyList(); } return ourStandardScripts; } @@ -307,18 +338,11 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { List result = new ArrayList(); - try { - for (Pair pair : getStandardScripts()) { - result.add(new GroovyDslScript(project, null, pair.second, pair.first.getPath())); - } + for (Pair pair : getStandardScripts()) { + result.add(new GroovyDslScript(project, null, pair.second, pair.first.getPath())); } - catch (OutOfMemoryError e) { - stopGdsl = true; - throw e; - } - catch (NoClassDefFoundError e) { - stopGdsl = true; - throw e; + if (stopGdsl) { + return Result.create(Collections.emptyList()); } final LinkedBlockingQueue> queue = diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index b1a9ffdd5443..cba609eeb069 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -42,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrM import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.*; @@ -129,6 +130,10 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { } private void handlePossibleReturn(GrStatement last) { + //last statement inside finally clause cannot be possible return statement + final GrFinallyClause finallyClause = PsiTreeUtil.getParentOfType(last, GrFinallyClause.class, false, GrClosableBlock.class, GrMember.class); + if (finallyClause != null) return; + if (last instanceof GrExpression && PsiTreeUtil.isAncestor(myLastInScope, last, false)) { final MaybeReturnInstruction instruction = new MaybeReturnInstruction((GrExpression)last, myInstructionNumber++); checkPending(instruction); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index 506ad61d9aeb..426bc7760f18 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -635,4 +635,11 @@ public class TypesUtil { return PsiImplUtil.normalizeWildcardTypeByPosition(type, expression); } + @Nullable + public static PsiType getItemType(@Nullable PsiType containerType) { + if (containerType == null) return null; + + if (containerType instanceof PsiArrayType) return ((PsiArrayType)containerType).getComponentType(); + return PsiUtil.extractIterableTypeParameter(containerType, false); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java index fff5e52bb71d..623e70b1c6c0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java @@ -188,8 +188,8 @@ public class GrLiteralImpl extends GrAbstractLiteral implements GrLiteral, PsiLa public GrLiteralImpl updateText(@NotNull final String text) { final GrExpression newExpr = GroovyPsiElementFactory.getInstance(getProject()).createExpressionFromText(text); - LOG.assertTrue(newExpr instanceof GrLiteral); - LOG.assertTrue(newExpr.getFirstChild() != null); + LOG.assertTrue(newExpr instanceof GrLiteral, text); + LOG.assertTrue(newExpr.getFirstChild() != null, text); final ASTNode valueNode = getNode().getFirstChildNode(); getNode().replaceChild(valueNode, newExpr.getFirstChild().getNode()); return this; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java index f22d85c68a4b..8c6a08d416df 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java @@ -20,13 +20,14 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ResolveCache; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.NullableFunction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -37,19 +38,51 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import java.util.HashMap; + +import static com.intellij.psi.CommonClassNames.JAVA_UTIL_COLLECTION; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.kAS; + /** * @author ven */ public class GrSafeCastExpressionImpl extends GrExpressionImpl implements GrSafeCastExpression, PsiPolyVariantReference { - private static final Function TYPE_CALCULATOR = new NullableFunction() { - @Override - public PsiType fun(GrSafeCastExpressionImpl cast) { - GrTypeElement typeElement = cast.getCastTypeElement(); - if (typeElement != null) return TypesUtil.boxPrimitiveType(typeElement.getType(), cast.getManager(), cast.getResolveScope()); - return null; - } - }; + private static final Function TYPE_CALCULATOR = + new NullableFunction() { + @Override + public PsiType fun(GrSafeCastExpressionImpl cast) { + GrTypeElement typeElement = cast.getCastTypeElement(); + if (typeElement == null) return null; + + final PsiType opType = cast.getOperand().getType(); + final PsiType castType = typeElement.getType(); + + if (isCastToRawCollectionFromArray(opType, castType)) { + final PsiClass resolved = ((PsiClassType)castType).resolve(); + final PsiTypeParameter typeParameter = resolved.getTypeParameters()[0]; + final HashMap substitutionMap = new HashMap(); + substitutionMap.put(typeParameter, TypesUtil.getItemType(opType)); + final PsiSubstitutor substitutor = JavaPsiFacade.getElementFactory(cast.getProject()).createSubstitutor(substitutionMap); + return JavaPsiFacade.getElementFactory(cast.getProject()).createType(resolved, substitutor); + } + + return TypesUtil.boxPrimitiveType(castType, cast.getManager(), cast.getResolveScope()); + } + }; + + + /** + * It is assumed that collection class should have only one type param and this param defines collection's item type. + */ + private static boolean isCastToRawCollectionFromArray(PsiType opType, PsiType castType) { + return castType instanceof PsiClassType && + InheritanceUtil.isInheritor(castType, JAVA_UTIL_COLLECTION) && + PsiUtil.extractIterableTypeParameter(castType, false) == null && + ((PsiClassType)castType).resolve().getTypeParameters().length == 1 && + TypesUtil.getItemType(opType) != null; + } + private static final class OurResolver implements ResolveCache.PolyVariantResolver { @Override @@ -61,12 +94,8 @@ public class GrSafeCastExpressionImpl extends GrExpressionImpl implements GrSafe final GrTypeElement typeElement = cast.getCastTypeElement(); final PsiType toCast = typeElement == null ? null : typeElement.getType(); - return TypesUtil.getOverloadedOperatorCandidates( - type, - GroovyTokenTypes.kAS, - cast, - new PsiType[]{TypesUtil.createJavaLangClassType(toCast, cast.getProject(), cast.getResolveScope())} - ); + final PsiType classType = TypesUtil.createJavaLangClassType(toCast, cast.getProject(), cast.getResolveScope()); + return TypesUtil.getOverloadedOperatorCandidates(type, kAS, cast, new PsiType[]{classType}); } } @@ -110,7 +139,7 @@ public class GrSafeCastExpressionImpl extends GrExpressionImpl implements GrSafe @Override public TextRange getRangeInElement() { - final PsiElement as = findNotNullChildByType(GroovyTokenTypes.kAS); + final PsiElement as = findNotNullChildByType(kAS); final int offset = as.getStartOffsetInParent(); return new TextRange(offset, offset + 2); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java index c41fa961bb22..ecf0703de053 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java @@ -74,6 +74,7 @@ import org.jetbrains.plugins.groovy.lang.psi.stubs.GrTypeDefinitionStub; import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.AstTransformContributor; +import org.jetbrains.plugins.groovy.runner.GroovyRunnerUtil; import org.jetbrains.plugins.groovy.util.LightCacheKey; import javax.swing.*; @@ -660,13 +661,18 @@ public abstract class GrTypeDefinitionImpl extends GrStubElementBase getVisibleSignatures() { - return Collections.emptySet(); + return PsiSuperMethodImplUtil.getVisibleSignatures(this); } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunnerUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunnerUtil.java index 4095acd7d992..d16af2cb14f5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunnerUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunnerUtil.java @@ -20,15 +20,12 @@ import com.intellij.psi.util.PsiMethodUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; /** * @author Max Medvedev */ public class GroovyRunnerUtil { - - private static final String JAVA_LANG_RUNNABLE = "java.lang.Runnable"; - @Nullable public static PsiClass getRunningClass(PsiElement element) { final PsiFile file = element.getContainingFile(); @@ -45,30 +42,18 @@ public class GroovyRunnerUtil { } public static boolean isRunnable(final PsiClass psiClass) { - if (!(psiClass instanceof GrTypeDefinition)) return false; - if (psiClass instanceof PsiAnonymousClass) return false; - if (psiClass.isInterface()) return false; - final PsiClass runnable = JavaPsiFacade.getInstance(psiClass.getProject()).findClass(JAVA_LANG_RUNNABLE, psiClass.getResolveScope()); + final PsiClass runnable = JavaPsiFacade.getInstance(psiClass.getProject()).findClass(CommonClassNames.JAVA_LANG_RUNNABLE, psiClass.getResolveScope()); if (runnable == null) return false; - final PsiMethod runMethod = runnable.getMethods()[0]; - final PsiMethod[] runImplementations = psiClass.findMethodsBySignature(runMethod, false); - if (runImplementations.length == 1 && - runImplementations[0] instanceof GrMethod && - ((GrMethod)runImplementations[0]).getBlock() != null) { - return psiClass.getContainingClass() == null || psiClass.hasModifierProperty(PsiModifier.STATIC); - } - return false; + + return psiClass instanceof GrTypeDefinition && + !(psiClass instanceof PsiAnonymousClass) && + !psiClass.isInterface() && + psiClass.isInheritor(runnable, true); } public static boolean canBeRunByGroovy(final PsiClass psiClass) { - if (isRunnable(psiClass)) { - return true; - } - - if (PsiMethodUtil.hasMainMethod(psiClass) && psiClass instanceof GrTypeDefinition) { - return true; - } - - return false; + return psiClass instanceof GroovyScriptClass || + isRunnable(psiClass) || + psiClass instanceof GrTypeDefinition && PsiMethodUtil.hasMainMethod(psiClass); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java index f57d42629f2b..4a53ff0b76d4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java @@ -50,7 +50,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.util.PathUtil; import com.intellij.util.SystemProperties; -import com.intellij.util.containers.hash.HashMap; +import com.intellij.util.containers.hash.LinkedHashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,7 +77,7 @@ public class GroovyScriptRunConfiguration extends ModuleBasedConfiguration envs = new HashMap(); + private final Map envs = new LinkedHashMap(); public boolean passParentEnv = true; public GroovyScriptRunConfiguration(final String name, final Project project, final ConfigurationFactory factory) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java index 67c81ff24225..198df9b8a6dc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java @@ -33,6 +33,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.extensions.GroovyScriptTypeDetector; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; + /** * @author ilyas */ @@ -56,7 +58,7 @@ public class GroovyScriptRunConfigurationProducer extends RuntimeConfigurationPr GroovyFile groovyFile = (GroovyFile)file; final PsiClass aClass = GroovyRunnerUtil.getRunningClass(location.getPsiElement()); - if (aClass != null && GroovyRunnerUtil.canBeRunByGroovy(aClass)) { + if (aClass instanceof GroovyScriptClass || GroovyRunnerUtil.isRunnable(aClass)) { final RunnerAndConfigurationSettings settings = createConfiguration(aClass); if (settings != null) { mySourceElement = element; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index fb4b05585d9d..bd693a882af2 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -96,7 +96,7 @@ public class GroovyCompletionTest extends GroovyCompletionTestBase { } public void testNamedParametersForConstructorCall() throws Throwable { - doVariantableTest("hahaha", "hohoho"); + doVariantableTest("hahaha", "hohoho", "hashCode"); } public void testUnfinishedMethodTypeParameter() throws Throwable { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy index 34b0e7071039..3a1bcf6f4038 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy @@ -59,11 +59,11 @@ public class GroovySmartCompletionTest extends GroovyCompletionTestBase { } public void testReturnStatement() throws Exception { - doSmartCompletion("b", "b1", "b2", "foo"); + doSmartCompletion("b", "b1", "b2", "equals", "foo"); } public void testIncSmartCompletion() throws Exception { - doSmartCompletion("a", "b"); + doSmartCompletion("a", "b", "hashCode"); } public void testInheritConstructorsAnnotation() throws Throwable { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index d21f6e8bb545..bad29401c92a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -43,7 +43,6 @@ import org.jetbrains.plugins.groovy.codeInspection.control.GroovyTrivialConditio import org.jetbrains.plugins.groovy.codeInspection.control.GroovyTrivialIfInspection import org.jetbrains.plugins.groovy.codeInspection.control.GroovyUnnecessaryReturnInspection import org.jetbrains.plugins.groovy.codeInspection.metrics.GroovyOverlyLongMethodInspection -import org.jetbrains.plugins.groovy.codeInspection.noReturnMethod.MissingReturnInspection import org.jetbrains.plugins.groovy.codeInspection.unassignedVariable.UnassignedVariableAccessInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUnresolvedAccessInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUntypedAccessInspection @@ -502,10 +501,6 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { doTest(new GroovyAssignabilityCheckInspection()); } - public void testMissingReturnInClosure() { - doTest(new MissingReturnInspection()); - } - public void testImmutableConstructorFromJava() { myFixture.addFileToProject "a.groovy", '''@groovy.transform.Immutable class Foo { int a; String b }''' myFixture.configureByText 'a.java', ''' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/MissingReturnTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/MissingReturnTest.groovy similarity index 82% rename from plugins/groovy/test/org/jetbrains/plugins/groovy/lang/MissingReturnTest.java rename to plugins/groovy/test/org/jetbrains/plugins/groovy/lang/MissingReturnTest.groovy index 3b16e743955d..e85cc9cd0a44 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/MissingReturnTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/MissingReturnTest.groovy @@ -1,10 +1,11 @@ package org.jetbrains.plugins.groovy.lang; -import com.intellij.testFramework.LightProjectDescriptor; -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.codeInspection.noReturnMethod.MissingReturnInspection; -import org.jetbrains.plugins.groovy.util.TestUtils; + +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.groovy.codeInspection.noReturnMethod.MissingReturnInspection +import org.jetbrains.plugins.groovy.util.TestUtils /** * @author peter @@ -13,7 +14,7 @@ public class MissingReturnTest extends LightCodeInsightFixtureTestCase { @Override protected String getBasePath() { - return TestUtils.getTestDataPath() + "highlighting/missingReturn"; + return "${TestUtils.testDataPath}highlighting/missingReturn"; } @NotNull @@ -38,8 +39,10 @@ public class MissingReturnTest extends LightCodeInsightFixtureTestCase { public void testExceptionWithFinally() throws Throwable {doTest();} public void testOnlyAssert() throws Throwable {doTest();} public void testImplicitReturnNull() throws Throwable {doTest();} + public void testMissingReturnInClosure() {doTest();} + public void testFinally() {doTest();} - private void doTest() throws Exception { + private void doTest() { myFixture.enableInspections(new MissingReturnInspection()); myFixture.testHighlighting(true, false, false, getTestName(false) + ".groovy"); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java index 02fceb5c7d89..a6790d48e8d5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java @@ -48,6 +48,7 @@ public class ControlFlowTest extends LightCodeInsightFixtureTestCase { public void testTry6() throws Throwable { doTest(); } public void testTry7() throws Throwable { doTest(); } public void testTry8() throws Throwable { doTest(); } + public void testTry9() throws Throwable { doTest(); } public void testWhile1() throws Throwable { doTest(); } public void testWhile2() throws Throwable { doTest(); } public void testWhileNonConstant() throws Throwable { doTest(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy index 82b35dc4ee20..13c9715cb507 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy @@ -28,6 +28,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType import org.jetbrains.plugins.groovy.util.TestUtils + import static com.intellij.psi.CommonClassNames.JAVA_LANG_INTEGER import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING @@ -306,4 +307,14 @@ X x = [:] def type = ((myFixture.file as GroovyFile).statements[0] as GrVariableDeclaration).variables[0].initializerGroovy.type assertEquals("java.util.Map", type.canonicalText) } + + void testRawCollectionsInCasts() { + def file = myFixture.configureByText('_a.groovy', '''\ +String[] a = ["a"] +def b = a as ArrayList +def cc = b[0] +print cc''') + def ref = (GrReferenceExpression)file.findReferenceAt(myFixture.editor.caretModel.offset) + assertEquals(String.canonicalName, ref.type.canonicalText) + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/changeSignature/ChangeSignatureForJavaTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/changeSignature/ChangeSignatureForJavaTest.java index 116ab24595f3..d28bcee4702b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/changeSignature/ChangeSignatureForJavaTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/changeSignature/ChangeSignatureForJavaTest.java @@ -160,7 +160,7 @@ public class ChangeSignatureForJavaTest extends LightCodeInsightFixtureTestCase } public void testCovariantReturnType() throws Exception { - doTest("java.lang.Runnable", new ParameterInfoImpl[0], false); + doTest(CommonClassNames.JAVA_LANG_RUNNABLE, new ParameterInfoImpl[0], false); } public void testReorderExceptions() throws Exception { diff --git a/plugins/groovy/testdata/groovy/controlFlow/throwInCatch.test b/plugins/groovy/testdata/groovy/controlFlow/throwInCatch.test index b8237a32e448..b05b85f0dedc 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/throwInCatch.test +++ b/plugins/groovy/testdata/groovy/controlFlow/throwInCatch.test @@ -16,10 +16,9 @@ try { 7(9) THROW. element: THROW statement 8(13) element: Finally clause 9(8,10) CALL 8 -10(16) AFTER CALL 9 +10(15) AFTER CALL 9 11(8,12) CALL 8 -12(16) AFTER CALL 11 +12(15) AFTER CALL 11 13(14) READ c -14(15) element: Reference expression MAYBE_RETURN -15(10,12) RETURN -16() element: null \ No newline at end of file +14(10,12) RETURN +15() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try2.test b/plugins/groovy/testdata/groovy/controlFlow/try2.test index 835e5ce092a5..2d9bfa5e59fc 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try2.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try2.test @@ -16,10 +16,9 @@ try { 7(11) element: Reference expression MAYBE_RETURN 8(13) element: Finally clause 9(8,10) CALL 8 -10(16) AFTER CALL 9 +10(15) AFTER CALL 9 11(8,12) CALL 8 -12(16) AFTER CALL 11 +12(15) AFTER CALL 11 13(14) READ c -14(15) element: Reference expression MAYBE_RETURN -15(10,12) RETURN -16() element: null \ No newline at end of file +14(10,12) RETURN +15() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try3.test b/plugins/groovy/testdata/groovy/controlFlow/try3.test index e88ebfd82e57..91fe04bc0eb9 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try3.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try3.test @@ -15,10 +15,9 @@ try { 5(9) element: Assignment expression MAYBE_RETURN 6(11) element: Finally clause 7(6,8) CALL 6 -8(14) AFTER CALL 7 +8(13) AFTER CALL 7 9(6,10) CALL 6 -10(14) AFTER CALL 9 +10(13) AFTER CALL 9 11(12) READ a -12(13) element: Method call MAYBE_RETURN -13(8,10) RETURN -14() element: null \ No newline at end of file +12(8,10) RETURN +13() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try7.test b/plugins/groovy/testdata/groovy/controlFlow/try7.test index 07bc70367be7..42a3ff079d91 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try7.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try7.test @@ -11,10 +11,9 @@ try { 4(6) element: RETURN statement 5(10) element: Finally clause 6(5,7) CALL 5 -7(13) AFTER CALL 6 +7(12) AFTER CALL 6 8(5,9) CALL 5 -9(13) AFTER CALL 8 +9(12) AFTER CALL 8 10(11) READ bar -11(12) element: Method call MAYBE_RETURN -12(7,9) RETURN -13() element: null \ No newline at end of file +11(7,9) RETURN +12() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try8.test b/plugins/groovy/testdata/groovy/controlFlow/try8.test index 4955a11bfddf..f3ec754ff9f2 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try8.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try8.test @@ -16,14 +16,13 @@ finally { 6(14) element: Method call MAYBE_RETURN 7(16) element: Finally clause 8(7,9) CALL 7 -9(19) AFTER CALL 8 +9(18) AFTER CALL 8 10(7,11) CALL 7 -11(19) AFTER CALL 10 +11(18) AFTER CALL 10 12(7,13) CALL 7 -13(19) AFTER CALL 12 +13(18) AFTER CALL 12 14(7,15) CALL 7 -15(19) AFTER CALL 14 +15(18) AFTER CALL 14 16(17) READ b -17(18) element: Method call MAYBE_RETURN -18(9,11,13,15) RETURN -19() element: null \ No newline at end of file +17(9,11,13,15) RETURN +18() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try9.test b/plugins/groovy/testdata/groovy/controlFlow/try9.test new file mode 100644 index 000000000000..398b63ba43e6 --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/try9.test @@ -0,0 +1,28 @@ +InputStream i = null + +try { + return 1; +} +finally { + try { + i.close() + } + catch (Exception ignored) { + + } +} +----- +0(1) element: null +1(2) WRITE i +2(3) element: Open block +3(5) element: RETURN statement +4(7) element: Finally clause +5(4,6) CALL 4 +6(13) AFTER CALL 5 +7(8) element: Open block +8(9) READ i +9(10,13) THROW. element: Method call +10(11) element: Catch clause +11(12) WRITE ignored +12(6) RETURN +13() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/IncorrectEscaping.groovy b/plugins/groovy/testdata/highlighting/IncorrectEscaping.groovy index e31518de0622..f578bc6b9af4 100644 --- a/plugins/groovy/testdata/highlighting/IncorrectEscaping.groovy +++ b/plugins/groovy/testdata/highlighting/IncorrectEscaping.groovy @@ -14,5 +14,7 @@ print "dfg\$fg" print 'fg\$fg' print (/abc\n\r\y\o \u12 /) print (/abc\n\r\y\o \u1234 /) +print '\123\123' +print '\198' print """\n${x}\""" \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/missingReturn/Finally.groovy b/plugins/groovy/testdata/highlighting/missingReturn/Finally.groovy new file mode 100644 index 000000000000..ea470aa456ef --- /dev/null +++ b/plugins/groovy/testdata/highlighting/missingReturn/Finally.groovy @@ -0,0 +1,26 @@ +int missing() { + InputStream i = null + + try { + return 1; + } + catch(Exception i) { + + } +} + +int ok() { + InputStream i = null + + try { + return 1; + } + finally { + try { + i.close() + } + catch (Exception ignored) { + + } + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/MissingReturnInClosure.groovy b/plugins/groovy/testdata/highlighting/missingReturn/MissingReturnInClosure.groovy similarity index 100% rename from plugins/groovy/testdata/highlighting/MissingReturnInClosure.groovy rename to plugins/groovy/testdata/highlighting/missingReturn/MissingReturnInClosure.groovy diff --git a/plugins/junit_rt/src/com/intellij/junit4/ClassAwareSuiteMethod.java b/plugins/junit_rt/src/com/intellij/junit4/ClassAwareSuiteMethod.java new file mode 100644 index 000000000000..88c68f360545 --- /dev/null +++ b/plugins/junit_rt/src/com/intellij/junit4/ClassAwareSuiteMethod.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2012 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.junit4; + +import org.junit.internal.runners.SuiteMethod; + +/** +* User: anna +* Date: 2/22/12 +*/ +class ClassAwareSuiteMethod extends SuiteMethod { + private final Class myKlass; + + public ClassAwareSuiteMethod(Class klass) throws Throwable { + super(klass); + myKlass = klass; + } + + public Class getKlass() { + return myKlass; + } +} diff --git a/plugins/junit_rt/src/com/intellij/junit4/IdeaSuite.java b/plugins/junit_rt/src/com/intellij/junit4/IdeaSuite.java index 0fdfb6bcf231..31d2e8bb70a6 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/IdeaSuite.java +++ b/plugins/junit_rt/src/com/intellij/junit4/IdeaSuite.java @@ -37,6 +37,11 @@ import java.util.*; class IdeaSuite extends Suite { private final String myName; + public IdeaSuite(List runners, String name) throws InitializationError { + super(null, runners); + myName = name; + } + public IdeaSuite(final RunnerBuilder builder, Class[] classes, String name) throws InitializationError { super(builder, classes); myName = name; @@ -59,12 +64,25 @@ class IdeaSuite extends Suite { return description; } + protected Description describeChild(Runner child) { + final Description superDescription = super.describeChild(child); + if (child instanceof ClassAwareSuiteMethod) { + final Description description = Description.createSuiteDescription(((ClassAwareSuiteMethod)child).getKlass()); + ArrayList children = superDescription.getChildren(); + for (int i = 0, size = children.size(); i < size; i++) { + description.addChild((Description)children.get(i)); + } + return description; + } + return superDescription; + } + protected List getChildren() { final List children = super.getChildren(); final Set allNames = new HashSet(); for (Iterator iterator = children.iterator(); iterator.hasNext();) { final Object child = iterator.next(); - allNames.add(((Runner)child).getDescription().getDisplayName()); + allNames.add(describeChild((Runner)child).getDisplayName()); } for (Iterator iterator = children.iterator(); iterator.hasNext();) { final Object child = iterator.next(); @@ -75,7 +93,7 @@ class IdeaSuite extends Suite { for (Iterator iterator = children.iterator(); iterator.hasNext(); ) { Object child = iterator.next(); - if (!allNames.contains(((Runner)child).getDescription().getDisplayName())) { + if (!allNames.contains(describeChild((Runner)child).getDisplayName())) { iterator.remove(); } } @@ -83,14 +101,14 @@ class IdeaSuite extends Suite { return children; } - private static void skipSuiteComponents(Set allNames, Object child) { + private void skipSuiteComponents(Set allNames, Object child) { try { if (child instanceof Suite) { final Method getChildrenMethod = Suite.class.getDeclaredMethod("getChildren", new Class[0]); getChildrenMethod.setAccessible(true); final List tests = (List)getChildrenMethod.invoke(child, new Object[0]); for (Iterator suiteIterator = tests.iterator(); suiteIterator.hasNext();) { - final String displayName = ((Runner)suiteIterator.next()).getDescription().getDisplayName(); + final String displayName = describeChild((Runner)suiteIterator.next()).getDisplayName(); if (allNames.contains(displayName)) { allNames.remove(displayName); } diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java index 697620d242e1..ef7961ff331a 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java @@ -21,13 +21,13 @@ package com.intellij.junit4; import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; +import org.junit.internal.builders.SuiteMethodBuilder; +import org.junit.internal.runners.ErrorReportingRunner; import org.junit.runner.Request; import org.junit.runner.Runner; import org.junit.runners.model.InitializationError; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; +import java.util.*; public class JUnit46ClassesRequestBuilder { private JUnit46ClassesRequestBuilder() {} @@ -35,8 +35,13 @@ public class JUnit46ClassesRequestBuilder { public static Request getClassesRequest(final String suiteName, Class[] classes, Map classMethods) { boolean canUseSuiteMethod = canUseSuiteMethod(classMethods); try { - final AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(canUseSuiteMethod); - final Runner suite = new IdeaSuite(builder, classes, suiteName); + final Runner suite; + if (canUseSuiteMethod) { + suite = new IdeaSuite(collectWrappedRunners(classes), suiteName); + } else { + final AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(canUseSuiteMethod); + suite = new IdeaSuite(builder, classes, suiteName); + } return Request.runner(suite); } catch (InitializationError e) { @@ -44,6 +49,27 @@ public class JUnit46ClassesRequestBuilder { } } + private static List collectWrappedRunners(Class[] classes) throws InitializationError { + final List runners = new ArrayList(); + final List nonSuiteClasses = new ArrayList(); + final SuiteMethodBuilder suiteMethodBuilder = new SuiteMethodBuilder(); + for (int i = 0, length = classes.length; i < length; i++) { + Class aClass = classes[i]; + if (suiteMethodBuilder.hasSuiteMethod(aClass)) { + try { + runners.add(new ClassAwareSuiteMethod(aClass)); + } + catch (Throwable throwable) { + runners.add(new ErrorReportingRunner(aClass, throwable)); + } + } else { + nonSuiteClasses.add(aClass); + } + } + runners.addAll(new AllDefaultPossibilitiesBuilder(false).runners(null, (Class[])nonSuiteClasses.toArray(new Class[nonSuiteClasses.size()]))); + return runners; + } + private static boolean canUseSuiteMethod(Map classMethods) { for (Iterator iterator = classMethods.keySet().iterator(); iterator.hasNext(); ) { Object className = iterator.next(); diff --git a/resources-en/src/messages/QuickFixBundle.properties b/resources-en/src/messages/QuickFixBundle.properties index 991d041eecce..504731f4d002 100644 --- a/resources-en/src/messages/QuickFixBundle.properties +++ b/resources-en/src/messages/QuickFixBundle.properties @@ -257,7 +257,7 @@ create.readable.property.with.field=Create getter and field for ''{0}'' create.writable.property.with.field=Create setter and field for ''{0}'' change.to.append.family=Fix StringBuilder append -change.to.append.text=Change to ''{0}.append({1})'' +change.to.append.text=Change to ''{0}'' convert.to.string.family=Fix Character Literal convert.to.string.text=Convert to String Literal