diff --git a/build/lib/gant/jps-sources.zip b/build/lib/gant/jps-sources.zip index 77e537d09b3f..22a95cbbb7bf 100644 Binary files a/build/lib/gant/jps-sources.zip and b/build/lib/gant/jps-sources.zip differ diff --git a/build/lib/gant/lib/jps-programRunner.jar b/build/lib/gant/lib/jps-programRunner.jar index 15799992ceb2..a28e71ec51e7 100644 Binary files a/build/lib/gant/lib/jps-programRunner.jar and b/build/lib/gant/lib/jps-programRunner.jar differ diff --git a/build/lib/gant/lib/jps.jar b/build/lib/gant/lib/jps.jar index d379f63b1a06..f90062046f2e 100644 Binary files a/build/lib/gant/lib/jps.jar and b/build/lib/gant/lib/jps.jar differ diff --git a/java/compiler/impl/src/com/intellij/openapi/deployment/DeploymentUtilImpl.java b/java/compiler/impl/src/com/intellij/openapi/deployment/DeploymentUtilImpl.java index 9968fdbe3fb6..d57d0f3c8d5b 100644 --- a/java/compiler/impl/src/com/intellij/openapi/deployment/DeploymentUtilImpl.java +++ b/java/compiler/impl/src/com/intellij/openapi/deployment/DeploymentUtilImpl.java @@ -50,6 +50,9 @@ public class DeploymentUtilImpl extends DeploymentUtil { @Nullable Set writtenPaths, @Nullable FileFilter fileFilter) throws IOException { if (fileFilter != null && !fileFilter.accept(fromFile)) { + if (LOG.isDebugEnabled()) { + LOG.debug("Skipping " + fromFile.getAbsolutePath() + ": it wasn't accepted by filter " + fileFilter); + } return; } checkPathDoNotNavigatesUpFromFile(fromFile); @@ -69,13 +72,19 @@ public class DeploymentUtilImpl extends DeploymentUtil { } if (fromFile.equals(toFile) || writtenPaths != null && !writtenPaths.add(toFile.getPath())) { + if (LOG.isDebugEnabled()) { + LOG.debug("Skipping " + fromFile.getAbsolutePath() + ": " + toFile.getAbsolutePath() + " is already written"); + } return; } - if (!FileUtil.isFilePathAcceptable(toFile, fileFilter)) return; - if (context.getProgressIndicator() != null) { - context.getProgressIndicator().setText("Copying files"); - context.getProgressIndicator().setText2(fromFile.getPath()); + if (!FileUtil.isFilePathAcceptable(toFile, fileFilter)) { + if (LOG.isDebugEnabled()) { + LOG.debug("Skipping " + fromFile.getAbsolutePath() + ": " + toFile.getAbsolutePath() + " wasn't accepted by filter " + fileFilter); + } + return; } + context.getProgressIndicator().setText("Copying files"); + context.getProgressIndicator().setText2(fromFile.getPath()); try { if (LOG.isDebugEnabled()) { LOG.debug("Copy file '" + fromFile + "' to '"+toFile+"'"); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 2f3fb0439645..3fdec5e8cdee 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -694,7 +694,7 @@ public class HighlightControlFlowUtil { return highlightInfo; } else { final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(context, PsiLambdaExpression.class); - if (lambdaExpression != null) { + if (lambdaExpression != null && !PsiTreeUtil.isAncestor(lambdaExpression, variable, true)) { boolean effectivelyFinal; if (variable instanceof PsiParameter) { final PsiElement parent = variable.getParent(); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/BindFieldsFromParametersAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BindFieldsFromParametersAction.java index 9b34522e6046..5566f3778c5c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/BindFieldsFromParametersAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BindFieldsFromParametersAction.java @@ -266,7 +266,17 @@ public class BindFieldsFromParametersAction extends BaseIntentionAction implemen String[] names = suggestedNameInfo.names; final boolean isFinal = !isMethodStatic && method.isConstructor(); - final String fieldName = usedNames.add(names[0]) ? names[0] : JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(names[0], myParameter, true); + String name = names[0]; + if (targetClass != null) { + for (String curName : names) { + if (!usedNames.contains(curName) && targetClass.findFieldByName(curName, false) != null) { + name = curName; + break; + } + } + } + final String fieldName = usedNames.add(name) ? name + : JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(name, myParameter, true); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFieldNameIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFieldNameIndex.java index 463a69e8f213..54eb0edf6a05 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFieldNameIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFieldNameIndex.java @@ -46,9 +46,4 @@ public class JavaFieldNameIndex extends StringStubIndexExtension { public Collection get(final String s, final Project project, @NotNull final GlobalSearchScope scope) { return super.get(s, project, new JavaSourceFilterScope(scope)); } - - @Override - public boolean isKeyHighlySelective() { - return true; - } } \ No newline at end of file diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFullClassNameIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFullClassNameIndex.java index 1b2bdd4088ad..40c75f3551b3 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFullClassNameIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaFullClassNameIndex.java @@ -46,9 +46,4 @@ public class JavaFullClassNameIndex extends IntStubIndexExtension { public Collection get(final Integer integer, final Project project, @NotNull final GlobalSearchScope scope) { return super.get(integer, project, new JavaSourceFilterScope(scope)); } - - @Override - public boolean isKeyHighlySelective() { - return true; - } } \ No newline at end of file diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodNameIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodNameIndex.java index fa8e2a0a91d2..a92856f2564c 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodNameIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodNameIndex.java @@ -46,9 +46,4 @@ public class JavaMethodNameIndex extends StringStubIndexExtension { public Collection get(final String s, final Project project, @NotNull final GlobalSearchScope scope) { return super.get(s, project, new JavaSourceFilterScope(scope)); } - - @Override - public boolean isKeyHighlySelective() { - return true; - } } \ No newline at end of file diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java index 1e864f7054c7..5cd6454bf26e 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java @@ -46,9 +46,4 @@ public class JavaShortClassNameIndex extends StringStubIndexExtension public Collection get(final String s, final Project project, @NotNull final GlobalSearchScope scope) { return super.get(s, project, new JavaSourceFilterScope(scope)); } - - @Override - public boolean isKeyHighlySelective() { - return true; - } } \ No newline at end of file diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberNameIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberNameIndex.java index 3787bdf6d955..3cb51d985720 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberNameIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberNameIndex.java @@ -45,9 +45,4 @@ public class JavaStaticMemberNameIndex extends StringStubIndexExtension getStaticMembers(final String name, final Project project, @NotNull final GlobalSearchScope scope) { return super.get(name, project, new JavaSourceFilterScope(scope)); } - - @Override - public boolean isKeyHighlySelective() { - return true; - } } \ No newline at end of file diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberTypeIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberTypeIndex.java index baf5ec5bfdef..3898c730ee7e 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberTypeIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStaticMemberTypeIndex.java @@ -45,9 +45,4 @@ public class JavaStaticMemberTypeIndex extends StringStubIndexExtension getStaticMembers(@NotNull final String shortTypeText, final Project project, @NotNull final GlobalSearchScope scope) { return super.get(shortTypeText, project, new JavaSourceFilterScope(scope)); } - - @Override - public boolean isKeyHighlySelective() { - return true; - } } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java index 60cf15798689..27df244ce488 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java @@ -86,7 +86,8 @@ public class ReplaceExpressionUtil { else if (i == JavaElementType.LITERAL_EXPRESSION || i == JavaElementType.THIS_EXPRESSION || i == JavaElementType.SUPER_EXPRESSION || - i == JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION) { + i == JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION || + i == JavaElementType.LAMBDA_EXPRESSION) { return false; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA89771.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA89771.java new file mode 100644 index 000000000000..f3a04de113f2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA89771.java @@ -0,0 +1,3 @@ +public @interface MyAnnotation { + Class> enumClass() default Enum.class; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA89801.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA89801.java new file mode 100644 index 000000000000..28d970737d2f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA89801.java @@ -0,0 +1,7 @@ +import java.util.*; +class Test { + { + Map map1 = null; + Map map2 = (Map) map1; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java index 7bb3238625db..2636112628a0 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java @@ -70,3 +70,24 @@ public class XXX { foo(() -> y=1); } } + +class Sample { + public static void main(String[] args) { + Runnable runnable = () -> { + Integer i; + if (true) { + i = 111; + System.out.println(i); + } + }; + + Runnable runnable2 = () -> { + Integer i2 = 333; + i2 = 444; + System.out.println(i2); + }; + + runnable.run(); // prints 111 + runnable2.run(); // prints 444 + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/bindFieldsFromParameters/afterAlreadyExistingFields.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/bindFieldsFromParameters/afterAlreadyExistingFields.java new file mode 100644 index 000000000000..acee0e0a79a3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/bindFieldsFromParameters/afterAlreadyExistingFields.java @@ -0,0 +1,14 @@ +// "Bind Method Parameters to Fields" "true" + +class A{ + private final String myP; + private final String myLongParameterName; + private final String myName; + + void f(String p, String longParameterName, String shortParameterName){ + myP = p; + myLongParameterName = longParameterName; + myName = shortParameterName; + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/bindFieldsFromParameters/beforeAlreadyExistingFields.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/bindFieldsFromParameters/beforeAlreadyExistingFields.java new file mode 100644 index 000000000000..eae2e0b2090c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/bindFieldsFromParameters/beforeAlreadyExistingFields.java @@ -0,0 +1,11 @@ +// "Bind Method Parameters to Fields" "true" + +class A{ + private final String myP; + private final String myLongParameterName; + private final String myName; + + void f(String p, String longParameterName, String shortParameterName){ + } +} + diff --git a/java/java-tests/testData/inspection/redundantCast/generics/CastToUnboundWildcard/expected.xml b/java/java-tests/testData/inspection/redundantCast/generics/CastToUnboundWildcard/expected.xml new file mode 100644 index 000000000000..4704d91e891d --- /dev/null +++ b/java/java-tests/testData/inspection/redundantCast/generics/CastToUnboundWildcard/expected.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/redundantCast/generics/CastToUnboundWildcard/src/Test.java b/java/java-tests/testData/inspection/redundantCast/generics/CastToUnboundWildcard/src/Test.java new file mode 100644 index 000000000000..bf7e46e214d4 --- /dev/null +++ b/java/java-tests/testData/inspection/redundantCast/generics/CastToUnboundWildcard/src/Test.java @@ -0,0 +1,9 @@ +import java.util.*; +import java.util.Map; + +class Test { + { + Map map1 = null; + Map map2 = (Map) (Map) map1; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index 9142b65b3ba1..191c956e498d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -136,6 +136,8 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIllegalGenericTypeInInstanceof() throws Exception {doTest(false);} public void testIDEA57339() throws Exception {doTest(false);} public void testIDEA57340() throws Exception {doTest(false);} + public void testIDEA89771() throws Exception {doTest(false);} + public void testIDEA89801() throws Exception {doTest(false);} public void testInconvertibleTypes() throws Exception {doTest(false);} public void testJavaUtilCollections_NoVerify() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LambdaParamsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LambdaParamsTest.java deleted file mode 100644 index 6eba6532c120..000000000000 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LambdaParamsTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.codeInsight.daemon; - -import org.jetbrains.annotations.NonNls; - -public class LambdaParamsTest extends LightDaemonAnalyzerTestCase { - @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/params"; - - public void testFormalParams() throws Exception { - doTest(); - } - - public void testInferredParams() throws Exception { - doTest(); - } - - public void testMethodApplicability() throws Exception { - doTest(); - } - - private void doTest() throws Exception { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false); - } -} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java index 71f07757ffec..d235bc43b2e1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java @@ -37,6 +37,7 @@ public class RedundantCast15Test extends InspectionTestCase { public void testEnumConstant() throws Exception { doTest(); } public void testRawCast() throws Exception { doTest();} + public void testCastToUnboundWildcard() throws Exception { doTest();} public void testRawCastsToAvoidIncompatibility() throws Exception { doTest();} diff --git a/java/java-tests/testSrc/com/intellij/psi/PsiDocumentManagerImplTest.java b/java/java-tests/testSrc/com/intellij/psi/PsiDocumentManagerImplTest.java index 09f913884a1a..aaad3fd96aaa 100644 --- a/java/java-tests/testSrc/com/intellij/psi/PsiDocumentManagerImplTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/PsiDocumentManagerImplTest.java @@ -1,3 +1,18 @@ +/* + * 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.psi; import com.intellij.ide.impl.ProjectUtil; @@ -219,8 +234,10 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { public void testCommitInBackground() { PsiFile file = getPsiManager().findFile(createFile()); + assertNotNull(file); assertTrue(file.isPhysical()); final Document document = getPsiDocumentManager().getDocument(file); + assertNotNull(document); final Semaphore semaphore = new Semaphore(); semaphore.down(); @@ -231,7 +248,7 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { semaphore.up(); } }); - waitAndPump(semaphore); + waitAndPump(semaphore, 30000); assertTrue(getPsiDocumentManager().isCommitted(document)); ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -249,7 +266,7 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { semaphore.up(); } }); - waitAndPump(semaphore); + waitAndPump(semaphore, 30000); assertTrue(getPsiDocumentManager().isCommitted(document)); final AtomicInteger count = new AtomicInteger(); @@ -298,10 +315,13 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { assertEquals(2, count.get()); } - private static void waitAndPump(Semaphore semaphore) { - while (!semaphore.waitFor(10)) { + private static void waitAndPump(Semaphore semaphore, int timeout) { + final long limit = System.currentTimeMillis() + timeout; + while (System.currentTimeMillis() < limit) { + if (semaphore.waitFor(10)) return; UIUtil.dispatchAllInvocationEvents(); } + fail("Timeout"); } public void testDocumentFromAlienProjectGetsCommittedInBackground() throws Exception { diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java index 4128284bfae2..2e800430295d 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java @@ -28,6 +28,7 @@ import org.jetbrains.jps.incremental.BuildLoggingManager; import org.jetbrains.jps.incremental.CompileScope; import org.jetbrains.jps.incremental.IncProjectBuilder; import org.jetbrains.jps.incremental.java.JavaBuilderLoggerImpl; +import org.jetbrains.jps.model.JpsElementFactory; import org.jetbrains.jps.model.artifact.DirectoryArtifactType; import org.jetbrains.jps.model.artifact.JpsArtifact; import org.jetbrains.jps.model.artifact.JpsArtifactService; @@ -114,7 +115,8 @@ public abstract class ArtifactBuilderTestCase extends JpsBuildTestCase { protected JpsArtifact addArtifact(String name, LayoutElementTestUtil.LayoutElementCreator root) { assertFalse("JpsArtifact " + name + " already exists", getArtifactNames().contains(name)); - JpsArtifact artifact = JpsArtifactService.getInstance().addArtifact(myJpsProject, name, root.buildElement(), DirectoryArtifactType.INSTANCE); + JpsArtifact artifact = JpsArtifactService.getInstance().addArtifact(myJpsProject, name, root.buildElement(), DirectoryArtifactType.INSTANCE, + JpsElementFactory.getInstance().createDummyElement()); artifact.setOutputPath(getAbsolutePath("out/artifacts/" + name)); return artifact; } diff --git a/jps/model-api/src/org/jetbrains/jps/model/artifact/DirectoryArtifactType.java b/jps/model-api/src/org/jetbrains/jps/model/artifact/DirectoryArtifactType.java index 0a606c3490d5..bceae8bfa3a1 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/artifact/DirectoryArtifactType.java +++ b/jps/model-api/src/org/jetbrains/jps/model/artifact/DirectoryArtifactType.java @@ -1,8 +1,10 @@ package org.jetbrains.jps.model.artifact; +import org.jetbrains.jps.model.JpsDummyElement; + /** * @author nik */ -public class DirectoryArtifactType extends JpsArtifactType { +public class DirectoryArtifactType extends JpsArtifactType { public static final DirectoryArtifactType INSTANCE = new DirectoryArtifactType(); } diff --git a/jps/model-api/src/org/jetbrains/jps/model/artifact/JarArtifactType.java b/jps/model-api/src/org/jetbrains/jps/model/artifact/JarArtifactType.java index 75552f36bf71..00a3a473a23d 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/artifact/JarArtifactType.java +++ b/jps/model-api/src/org/jetbrains/jps/model/artifact/JarArtifactType.java @@ -1,8 +1,10 @@ package org.jetbrains.jps.model.artifact; +import org.jetbrains.jps.model.JpsDummyElement; + /** * @author nik */ -public class JarArtifactType extends JpsArtifactType { +public class JarArtifactType extends JpsArtifactType { public static final JarArtifactType INSTANCE = new JarArtifactType(); } diff --git a/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifact.java b/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifact.java index 7a4526b555eb..0081740ce5c8 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifact.java +++ b/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifact.java @@ -3,6 +3,7 @@ package org.jetbrains.jps.model.artifact; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsCompositeElement; +import org.jetbrains.jps.model.JpsElement; import org.jetbrains.jps.model.JpsNamedElement; import org.jetbrains.jps.model.JpsReferenceableElement; import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement; @@ -12,7 +13,7 @@ import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement; */ public interface JpsArtifact extends JpsNamedElement, JpsReferenceableElement, JpsCompositeElement { @NotNull - JpsArtifactType getArtifactType(); + JpsArtifactType getArtifactType(); @Nullable String getOutputPath(); @@ -31,4 +32,6 @@ public interface JpsArtifact extends JpsNamedElement, JpsReferenceableElement JpsArtifact createArtifact(@NotNull String name, @NotNull JpsCompositePackagingElement rootElement, + @NotNull JpsArtifactType

type, @NotNull P properties); public abstract List getArtifacts(@NotNull JpsProject project); - public abstract JpsArtifact addArtifact(@NotNull JpsProject project, - @NotNull String name, - @NotNull JpsCompositePackagingElement rootElement, - @NotNull JpsArtifactType type); + public abstract

JpsArtifact addArtifact(@NotNull JpsProject project, @NotNull String name, + @NotNull JpsCompositePackagingElement rootElement, + @NotNull JpsArtifactType

type, @NotNull P properties); public abstract JpsArtifactReference createReference(@NotNull String artifactName); } diff --git a/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifactType.java b/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifactType.java index 811e1c0156b5..60495e0f42b3 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifactType.java +++ b/jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifactType.java @@ -1,14 +1,16 @@ package org.jetbrains.jps.model.artifact; -import org.jetbrains.jps.model.DummyJpsElementProperties; -import org.jetbrains.jps.model.JpsElementType; +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.JpsElementChildRole; /** * @author nik */ -public abstract class JpsArtifactType extends JpsElementType { - @Override - public DummyJpsElementProperties createCopy(DummyJpsElementProperties properties) { - return DummyJpsElementProperties.INSTANCE; +public abstract class JpsArtifactType

{ + private final JpsElementChildRole

myPropertiesRole = new JpsElementChildRole

(); + + public final JpsElementChildRole

getPropertiesRole() { + return myPropertiesRole; } + } diff --git a/jps/model-impl/src/org/jetbrains/jps/model/artifact/impl/JpsArtifactImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/artifact/impl/JpsArtifactImpl.java index cf1708f39b2b..aa35dcfcc607 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/artifact/impl/JpsArtifactImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/artifact/impl/JpsArtifactImpl.java @@ -3,42 +3,42 @@ package org.jetbrains.jps.model.artifact.impl; import com.intellij.openapi.util.Comparing; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.model.DummyJpsElementProperties; +import org.jetbrains.jps.model.JpsElement; import org.jetbrains.jps.model.JpsElementChildRole; import org.jetbrains.jps.model.artifact.JpsArtifact; import org.jetbrains.jps.model.artifact.JpsArtifactType; import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement; import org.jetbrains.jps.model.impl.JpsElementChildRoleBase; import org.jetbrains.jps.model.impl.JpsNamedCompositeElementBase; -import org.jetbrains.jps.model.impl.JpsTypedDataImpl; -import org.jetbrains.jps.model.impl.JpsTypedDataRole; /** * @author nik */ -public class JpsArtifactImpl extends JpsNamedCompositeElementBase implements JpsArtifact { +public class JpsArtifactImpl

extends JpsNamedCompositeElementBase> implements JpsArtifact { private static final JpsElementChildRole ROOT_ELEMENT_CHILD_ROLE = JpsElementChildRoleBase.create("root element"); - private static final JpsTypedDataRole TYPED_DATA_ROLE = new JpsTypedDataRole(); + private final JpsArtifactType

myArtifactType; private String myOutputPath; private boolean myBuildOnMake; - public JpsArtifactImpl(@NotNull String name, @NotNull JpsCompositePackagingElement rootElement, @NotNull JpsArtifactType type) { + public JpsArtifactImpl(@NotNull String name, @NotNull JpsCompositePackagingElement rootElement, @NotNull JpsArtifactType

type, @NotNull P properties) { super(name); + myArtifactType = type; myContainer.setChild(ROOT_ELEMENT_CHILD_ROLE, rootElement); - myContainer.setChild(TYPED_DATA_ROLE, new JpsTypedDataImpl(type, DummyJpsElementProperties.INSTANCE)); + myContainer.setChild(type.getPropertiesRole(), properties); } - private JpsArtifactImpl(JpsArtifactImpl original) { + private JpsArtifactImpl(JpsArtifactImpl

original) { super(original); + myArtifactType = original.myArtifactType; myOutputPath = original.myOutputPath; } @NotNull @Override - public JpsArtifactImpl createCopy() { - return new JpsArtifactImpl(this); + public JpsArtifactImpl

createCopy() { + return new JpsArtifactImpl

(this); } public String getOutputPath() { @@ -54,8 +54,8 @@ public class JpsArtifactImpl extends JpsNamedCompositeElementBase getArtifactType() { + return myArtifactType; } @NotNull @@ -75,6 +75,11 @@ public class JpsArtifactImpl extends JpsNamedCompositeElementBase getArtifacts(@NotNull JpsProject project) { JpsElementCollectionImpl collection = project.getContainer().getChild(JpsArtifactRole.ARTIFACT_COLLECTION_ROLE); @@ -23,15 +25,20 @@ public class JpsArtifactServiceImpl extends JpsArtifactService { } @Override - public JpsArtifact addArtifact(@NotNull JpsProject project, @NotNull String name, @NotNull JpsCompositePackagingElement rootElement, - @NotNull JpsArtifactType type) { - JpsArtifact artifact = createArtifact(name, rootElement, type); + public

JpsArtifact addArtifact(@NotNull JpsProject project, + @NotNull String name, + @NotNull JpsCompositePackagingElement rootElement, + @NotNull JpsArtifactType

type, + @NotNull P properties) { + JpsArtifact artifact = createArtifact(name, rootElement, type, properties); return project.getContainer().getOrSetChild(JpsArtifactRole.ARTIFACT_COLLECTION_ROLE).addChild(artifact); } + @Override - public JpsArtifact createArtifact(String name, JpsCompositePackagingElement rootElement, JpsArtifactType type) { - return new JpsArtifactImpl(name, rootElement, type); + public

JpsArtifact createArtifact(@NotNull String name, @NotNull JpsCompositePackagingElement rootElement, + @NotNull JpsArtifactType

type, @NotNull P properties) { + return new JpsArtifactImpl

(name, rootElement, type, properties); } @Override diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelSerializerExtension.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelSerializerExtension.java index 3ef2636b0ca3..73067004a957 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelSerializerExtension.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelSerializerExtension.java @@ -8,7 +8,7 @@ import org.jetbrains.jps.model.JpsElementReference; import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.module.JpsDependencyElement; import org.jetbrains.jps.model.module.JpsModule; -import org.jetbrains.jps.model.serialization.artifact.JpsArtifactTypeSerializer; +import org.jetbrains.jps.model.serialization.artifact.JpsArtifactPropertiesSerializer; import org.jetbrains.jps.model.serialization.artifact.JpsPackagingElementSerializer; import org.jetbrains.jps.model.serialization.facet.JpsModuleExtensionLoader; import org.jetbrains.jps.service.JpsServiceManager; @@ -83,7 +83,7 @@ public abstract class JpsModelSerializerExtension { return Collections.emptyList(); } - public List getArtifactTypeSerializers() { + public List> getArtifactTypePropertiesSerializers() { return Collections.emptyList(); } } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModulePropertiesSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModulePropertiesSerializer.java index 278150350bed..50bd56d966f0 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModulePropertiesSerializer.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModulePropertiesSerializer.java @@ -1,6 +1,7 @@ package org.jetbrains.jps.model.serialization; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsElement; import org.jetbrains.jps.model.module.JpsModuleType; @@ -14,4 +15,6 @@ public abstract class JpsModulePropertiesSerializer

extend } public abstract P loadProperties(@Nullable Element moduleRootElement); + + public abstract void saveProperties(@NotNull P properties, @NotNull Element moduleRootElement); } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java index 6d7acf03dcae..ff85a2dd92bb 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java @@ -180,6 +180,10 @@ public class JpsProjectLoader extends JpsLoaderBase { public JpsDummyElement loadProperties(@Nullable Element moduleRootElement) { return JpsElementFactory.getInstance().createDummyElement(); } + + @Override + public void saveProperties(@NotNull JpsDummyElement properties, @NotNull Element moduleRootElement) { + } }; } } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactDummyPropertiesSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactDummyPropertiesSerializer.java new file mode 100644 index 000000000000..36b111a774c4 --- /dev/null +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactDummyPropertiesSerializer.java @@ -0,0 +1,25 @@ +package org.jetbrains.jps.model.serialization.artifact; + +import org.jetbrains.jps.model.JpsDummyElement; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.artifact.JpsArtifactType; + +import java.util.List; + +/** + * @author nik + */ +public class JpsArtifactDummyPropertiesSerializer extends JpsArtifactPropertiesSerializer { + public JpsArtifactDummyPropertiesSerializer(String typeId, JpsArtifactType type) { + super(typeId, type); + } + + @Override + public JpsDummyElement loadProperties(List stateList) { + return JpsElementFactory.getInstance().createDummyElement(); + } + + @Override + public void saveProperties(JpsDummyElement properties, List stateList) { + } +} diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactPropertiesSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactPropertiesSerializer.java new file mode 100644 index 000000000000..361254ec2017 --- /dev/null +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactPropertiesSerializer.java @@ -0,0 +1,20 @@ +package org.jetbrains.jps.model.serialization.artifact; + +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.artifact.JpsArtifactType; +import org.jetbrains.jps.model.serialization.JpsElementPropertiesSerializer; + +import java.util.List; + +/** + * @author nik + */ +public abstract class JpsArtifactPropertiesSerializer

extends JpsElementPropertiesSerializer> { + public JpsArtifactPropertiesSerializer(String typeId, JpsArtifactType

type) { + super(type, typeId); + } + + public abstract P loadProperties(List stateList); + + public abstract void saveProperties(P properties, List stateList); +} diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactSerializer.java index 45828252b88b..8464e6cd3659 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactSerializer.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactSerializer.java @@ -6,10 +6,7 @@ import com.intellij.util.xmlb.XmlSerializer; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.model.JpsCompositeElement; -import org.jetbrains.jps.model.JpsElementFactory; -import org.jetbrains.jps.model.JpsElementReference; -import org.jetbrains.jps.model.JpsProject; +import org.jetbrains.jps.model.*; import org.jetbrains.jps.model.artifact.*; import org.jetbrains.jps.model.artifact.elements.*; import org.jetbrains.jps.model.library.JpsLibraryReference; @@ -31,9 +28,9 @@ public class JpsArtifactSerializer { new LibraryFilesElementSerializer(), new ArtifactOutputElementSerializer() }; - private static final JpsArtifactTypeSerializer[] STANDARD_TYPE_SERIALIZERS = { - new JpsArtifactTypeSerializer("plain", DirectoryArtifactType.INSTANCE), - new JpsArtifactTypeSerializer("jar", JarArtifactType.INSTANCE) + private static final JpsArtifactPropertiesSerializer[] STANDARD_TYPE_SERIALIZERS = { + new JpsArtifactDummyPropertiesSerializer("plain", DirectoryArtifactType.INSTANCE), + new JpsArtifactDummyPropertiesSerializer("jar", JarArtifactType.INSTANCE) }; private static final String ELEMENT_TAG = "element"; private static final String ID_ATTRIBUTE = "id"; @@ -45,13 +42,18 @@ public class JpsArtifactSerializer { for (Element artifactElement : JDOMUtil.getChildren(componentElement, "artifact")) { ArtifactState state = XmlSerializer.deserialize(artifactElement, ArtifactState.class); if (state == null) continue; - JpsArtifactType artifactType = getTypeSerializer(state.getArtifactType()).getType(); - JpsPackagingElement rootElement = loadPackagingElement(state.getRootElement()); - if (rootElement != null) { - JpsArtifact artifact = service.addArtifact(project, state.getName(), (JpsCompositePackagingElement)rootElement, artifactType); - artifact.setBuildOnMake(state.isBuildOnMake()); - artifact.setOutputPath(state.getOutputPath()); - } + JpsArtifactPropertiesSerializer serializer = getTypePropertiesSerializer(state.getArtifactType()); + loadArtifact(project, service, state, serializer); + } + } + + private static

void loadArtifact(JpsProject project, JpsArtifactService service, ArtifactState state, JpsArtifactPropertiesSerializer

serializer) { + JpsPackagingElement rootElement = loadPackagingElement(state.getRootElement()); + if (rootElement != null) { + JpsArtifact artifact = service.addArtifact(project, state.getName(), (JpsCompositePackagingElement)rootElement, + serializer.getType(), serializer.loadProperties(state.getPropertiesList())); + artifact.setBuildOnMake(state.isBuildOnMake()); + artifact.setOutputPath(state.getOutputPath()); } } @@ -60,8 +62,16 @@ public class JpsArtifactSerializer { state.setName(artifact.getName()); state.setBuildOnMake(artifact.isBuildOnMake()); state.setOutputPath(artifact.getOutputPath()); - state.setArtifactType(getTypeSerializer(artifact.getArtifactType()).getTypeId()); + JpsArtifactPropertiesSerializer serializer = getTypePropertiesSerializer(artifact.getArtifactType()); + doSaveArtifact(artifact, componentElement, state, serializer); + } + + private static

void doSaveArtifact(JpsArtifact artifact, Element componentElement, ArtifactState state, + JpsArtifactPropertiesSerializer

serializer) { + state.setArtifactType(serializer.getTypeId()); state.setRootElement(savePackagingElement(artifact.getRootElement())); + //noinspection unchecked + serializer.saveProperties((P)artifact.getProperties(), state.getPropertiesList()); componentElement.addContent(XmlSerializer.serialize(state, SERIALIZATION_FILTERS)); } @@ -138,14 +148,14 @@ public class JpsArtifactSerializer { throw new IllegalArgumentException("Serializer not found for " + elementClass); } - private static JpsArtifactTypeSerializer getTypeSerializer(String typeId) { - for (JpsArtifactTypeSerializer serializer : STANDARD_TYPE_SERIALIZERS) { + private static JpsArtifactPropertiesSerializer getTypePropertiesSerializer(String typeId) { + for (JpsArtifactPropertiesSerializer serializer : STANDARD_TYPE_SERIALIZERS) { if (serializer.getTypeId().equals(typeId)) { return serializer; } } for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { - for (JpsArtifactTypeSerializer serializer : extension.getArtifactTypeSerializers()) { + for (JpsArtifactPropertiesSerializer serializer : extension.getArtifactTypePropertiesSerializers()) { if (serializer.getTypeId().equals(typeId)) { return serializer; } @@ -154,14 +164,14 @@ public class JpsArtifactSerializer { return STANDARD_TYPE_SERIALIZERS[0]; } - private static JpsArtifactTypeSerializer getTypeSerializer(JpsArtifactType type) { - for (JpsArtifactTypeSerializer serializer : STANDARD_TYPE_SERIALIZERS) { + private static JpsArtifactPropertiesSerializer getTypePropertiesSerializer(JpsArtifactType type) { + for (JpsArtifactPropertiesSerializer serializer : STANDARD_TYPE_SERIALIZERS) { if (serializer.getType().equals(type)) { return serializer; } } for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { - for (JpsArtifactTypeSerializer serializer : extension.getArtifactTypeSerializers()) { + for (JpsArtifactPropertiesSerializer serializer : extension.getArtifactTypePropertiesSerializers()) { if (serializer.getType().equals(type)) { return serializer; } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactTypeSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactTypeSerializer.java deleted file mode 100644 index d694b8626190..000000000000 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactTypeSerializer.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.jetbrains.jps.model.serialization.artifact; - -import org.jetbrains.jps.model.artifact.JpsArtifactType; - -/** - * @author nik - */ -public class JpsArtifactTypeSerializer { - private final String myTypeId; - private final JpsArtifactType myType; - - public JpsArtifactTypeSerializer(String typeId, JpsArtifactType type) { - myTypeId = typeId; - myType = type; - } - - public String getTypeId() { - return myTypeId; - } - - public JpsArtifactType getType() { - return myType; - } -} diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java index 9130ba05db7e..85a991cd9278 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -30,14 +30,18 @@ public class VFileContentChangeEvent extends VFileEvent { private final long myOldModificationStamp; private final long myNewModificationStamp; - public VFileContentChangeEvent(final Object requestor, @NotNull VirtualFile file, long oldModificationStamp, long newModificationStamp, boolean isFromRefresh) { + public VFileContentChangeEvent(final Object requestor, + @NotNull final VirtualFile file, + final long oldModificationStamp, + final long newModificationStamp, + final boolean isFromRefresh) { super(requestor, isFromRefresh); - myFile = file; myOldModificationStamp = oldModificationStamp; myNewModificationStamp = newModificationStamp == -1 ? LocalTimeCounter.currentTime() : newModificationStamp; } + @NotNull @Override public VirtualFile getFile() { return myFile; diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java index 85d19906886e..42ff9d42d8a0 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -30,13 +30,14 @@ public class VFileMoveEvent extends VFileEvent { private final VirtualFile myOldParent; private final VirtualFile myNewParent; - public VFileMoveEvent(Object requestor, final VirtualFile file, final VirtualFile newParent) { + public VFileMoveEvent(final Object requestor, @NotNull final VirtualFile file, final VirtualFile newParent) { super(requestor, false); myFile = file; myNewParent = newParent; myOldParent = file.getParent(); } + @NotNull @Override public VirtualFile getFile() { return myFile; diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java index d8b7be67aab1..0d3d8da0ccf4 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -31,7 +31,12 @@ public class VFilePropertyChangeEvent extends VFileEvent { private final Object myOldValue; private final Object myNewValue; - public VFilePropertyChangeEvent(Object requestor, @NotNull VirtualFile file, @NotNull String propertyName, Object oldValue, Object newValue, boolean isFromRefresh) { + public VFilePropertyChangeEvent(final Object requestor, + @NotNull final VirtualFile file, + @NotNull final String propertyName, + final Object oldValue, + final Object newValue, + final boolean isFromRefresh) { super(requestor, isFromRefresh); myFile = file; myPropertyName = propertyName; @@ -39,6 +44,7 @@ public class VFilePropertyChangeEvent extends VFileEvent { myNewValue = newValue; } + @NotNull @Override public VirtualFile getFile() { return myFile; diff --git a/platform/indexing-api/src/com/intellij/psi/stubs/AbstractStubIndex.java b/platform/indexing-api/src/com/intellij/psi/stubs/AbstractStubIndex.java index 0d7d80de3299..da31e3233c96 100644 --- a/platform/indexing-api/src/com/intellij/psi/stubs/AbstractStubIndex.java +++ b/platform/indexing-api/src/com/intellij/psi/stubs/AbstractStubIndex.java @@ -34,9 +34,4 @@ public abstract class AbstractStubIndex implements } public int getCacheSize() { return 2 * 1024; } - - @Override - public boolean isKeyHighlySelective() { - return false; - } } diff --git a/platform/indexing-api/src/com/intellij/psi/stubs/StubIndexExtension.java b/platform/indexing-api/src/com/intellij/psi/stubs/StubIndexExtension.java index 5e55f874c114..741cab3f5247 100644 --- a/platform/indexing-api/src/com/intellij/psi/stubs/StubIndexExtension.java +++ b/platform/indexing-api/src/com/intellij/psi/stubs/StubIndexExtension.java @@ -36,6 +36,4 @@ public interface StubIndexExtension { KeyDescriptor getKeyDescriptor(); int getCacheSize(); - - boolean isKeyHighlySelective(); } \ No newline at end of file diff --git a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java index 424c5c75b004..387612fff350 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java @@ -140,9 +140,4 @@ public class FilenameIndex extends ScalarIndexExtension { } return files; } - - @Override - public boolean isKeyHighlySelective() { - return true; - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java index 865296f8eb9c..c21b0c903134 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java @@ -118,8 +118,9 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter { if (type == myLineCommentType) { final String restString = editorCharSequence.subSequence(caret, document.getLineEndOffset(lineNumber)).toString(); if (!StringUtil.isEmptyOrSpaces(restString)) { - EditorModificationUtil.insertStringAtCaret(editor, "\n" + lineIndent + myLineCommentPrefix); - editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(lineNumber + 1, 1)); + final String linePrefix = lineIndent + myLineCommentPrefix; + EditorModificationUtil.insertStringAtCaret(editor, "\n" + linePrefix); + editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(lineNumber + 1, linePrefix.length())); return Result.Stop; } else if (iterator.getStart() < lineStartOffset) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/wordSelection/NaturalLanguageTextSelectioner.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/wordSelection/NaturalLanguageTextSelectioner.java index 3e9ec968c08b..b6acd80a35f1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/wordSelection/NaturalLanguageTextSelectioner.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/wordSelection/NaturalLanguageTextSelectioner.java @@ -18,14 +18,14 @@ package com.intellij.codeInsight.editorActions.wordSelection; import com.intellij.codeInsight.editorActions.ExtendWordSelectionHandlerBase; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPlainText; import com.intellij.util.containers.CollectionFactory; +import org.jetbrains.annotations.Nullable; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; @@ -38,28 +38,31 @@ public class NaturalLanguageTextSelectioner extends ExtendWordSelectionHandlerBa return e instanceof PsiPlainText || e instanceof PsiComment; } - public List select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) { - final SelectionModel selectionModel = editor.getSelectionModel(); - if (!selectionModel.hasSelection()) { - return Collections.emptyList(); + private static TextRange findParagraphRange(String text, int start, int end) { + int paragraphStart = text.lastIndexOf("\n\n", start); + int paragraphEnd = text.indexOf("\n\n", end); + return new TextRange(paragraphStart >= 0 ? paragraphStart + 2 : 0, paragraphEnd < 0 ? text.length() : paragraphEnd); + } + + @Nullable + private static TextRange findCustomRange(String text, int start, int end, char startChar, char endChar) { + int prev = text.lastIndexOf(startChar, start); + int next = text.indexOf(endChar, end); + if (prev < 0 || next < 0) { + return null; + } + if (prev + 1 < start || next > end) { + return new TextRange(prev + 1, next); } - int sentenceStart = selectionModel.getSelectionStart(); - final int elementStart = e.getTextRange().getStartOffset(); - if (sentenceStart <= elementStart) return Collections.emptyList(); + return new TextRange(prev, next + 1); + } - int paragraphStart = editorText.subSequence(elementStart, sentenceStart).toString().lastIndexOf("\n\n"); - if (paragraphStart < 0) paragraphStart = elementStart; - else paragraphStart += 2 + elementStart; - boolean isParagraph = paragraphStart == sentenceStart; + private static TextRange findSentenceRange(String editorText, int start, int end) { + int sentenceStart = start; - while (sentenceStart > paragraphStart) { - final char c = editorText.charAt(sentenceStart - 1); - if (!isNatural(c)) { - return Collections.emptyList(); - } - - if (SENTENCE_END.contains(c)) { + while (sentenceStart > 0) { + if (isSentenceEnd(editorText, sentenceStart - 1) || !isNatural(editorText.charAt(sentenceStart - 1))) { break; } sentenceStart--; @@ -68,40 +71,90 @@ public class NaturalLanguageTextSelectioner extends ExtendWordSelectionHandlerBa sentenceStart++; } - int sentenceEnd = selectionModel.getSelectionEnd(); - final int elementEnd = e.getTextRange().getEndOffset(); - if (sentenceEnd > elementEnd) { - return Collections.emptyList(); - } - int paragraphEnd = editorText.subSequence(sentenceEnd, elementEnd).toString().indexOf("\n\n"); - if (paragraphEnd < 0) paragraphEnd = elementEnd; - else paragraphEnd += sentenceEnd; - isParagraph &= paragraphEnd == sentenceEnd; - - if (isParagraph) { - return Collections.emptyList(); //whole text - } - - if (sentenceEnd > elementStart) sentenceEnd--; - while (sentenceEnd < paragraphEnd) { - final char c = editorText.charAt(sentenceEnd); - if (!isNatural(c)) { - return Collections.emptyList(); - } + int sentenceEnd = Math.max(0, end - 1); + while (sentenceEnd < editorText.length()) { sentenceEnd++; - - if (SENTENCE_END.contains(c)) { + if (isSentenceEnd(editorText, sentenceEnd - 1)) { break; } + } + return new TextRange(sentenceStart, sentenceEnd); + } + private static boolean isSentenceEnd(String text, final int i) { + return SENTENCE_END.contains(text.charAt(i)) && (i + 1 == text.length() || Character.isWhitespace(text.charAt(i + 1))); + } + + private static TextRange findNaturalRange(String editorText, int start, int end) { + while (start > 0) { + if (!isNatural(editorText.charAt(start - 1))) { + break; + } + start--; } - if (sentenceStart == selectionModel.getSelectionStart() && sentenceEnd == selectionModel.getSelectionEnd()) { - return Arrays.asList(new TextRange(paragraphStart, paragraphEnd)); + while (end < editorText.length()) { + final char c = editorText.charAt(end); + if (!isNatural(c)) { + break; + } + end++; + } + return new TextRange(start, end); + } + + public List select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) { + TextRange range = expandSelection(e, editorText, cursorOffset, cursorOffset); + if (range == null) { + return Collections.emptyList(); } - return Arrays.asList(new TextRange(sentenceStart, sentenceEnd)); + ArrayList result = new ArrayList(); + result.add(range); + while (true) { + TextRange next = expandSelection(e, editorText, range.getStartOffset(), range.getEndOffset()); + if (next == null || next.equals(range)) { + break; + } + result.add(next); + range = next; + } + return result; + } + + @Nullable + private static TextRange expandSelection(PsiElement e, CharSequence editorText, int selStart, int selEnd) { + TextRange range = e.getTextRange(); + int shift = range.getStartOffset(); + if (selStart <= shift || selEnd >= range.getEndOffset()) { + return null; + } + + String elementText = editorText.subSequence(shift, range.getEndOffset()).toString(); + int start = selStart - shift; + int end = selEnd - shift; + + TextRange best = findSentenceRange(elementText, start, end); + best = narrowRange(best, findCustomRange(elementText, start, end, '\"', '\"')); + best = narrowRange(best, findCustomRange(elementText, start, end, '(', ')')); + + TextRange natural = findNaturalRange(elementText, start, end); + if (!natural.contains(best)) { + return null; + } + + TextRange paragraph = findParagraphRange(elementText, start, end); + if (best.getStartOffset() == start && best.getEndOffset() == end || !paragraph.contains(best)) { + return paragraph.shiftRight(shift); + } + + + return best.shiftRight(shift); + } + + private static TextRange narrowRange(TextRange best, TextRange candidate) { + return candidate != null && best.contains(candidate) ? candidate : best; } private static boolean isNatural(char c) { diff --git a/platform/lang-impl/src/com/intellij/conversion/ProjectConverter.java b/platform/lang-impl/src/com/intellij/conversion/ProjectConverter.java index 9424873251cc..08a7adea527f 100644 --- a/platform/lang-impl/src/com/intellij/conversion/ProjectConverter.java +++ b/platform/lang-impl/src/com/intellij/conversion/ProjectConverter.java @@ -60,6 +60,10 @@ public abstract class ProjectConverter { return Collections.emptyList(); } + public boolean isConversionNeeded() { + return false; + } + public void preProcessingFinished() throws CannotConvertException { } diff --git a/platform/lang-impl/src/com/intellij/conversion/impl/ConversionRunner.java b/platform/lang-impl/src/com/intellij/conversion/impl/ConversionRunner.java index 1130239e3cc2..25faa42183e0 100644 --- a/platform/lang-impl/src/com/intellij/conversion/impl/ConversionRunner.java +++ b/platform/lang-impl/src/com/intellij/conversion/impl/ConversionRunner.java @@ -75,7 +75,11 @@ public class ConversionRunner { myProcessProjectLibraries = myProjectLibrariesConverter != null && myProjectLibrariesConverter.isConversionNeeded(myContext.getProjectLibrariesSettings()); - return myProcessProjectFile || myProcessWorkspaceFile || myProcessRunConfigurations || !myModulesFilesToProcess.isEmpty(); + return myProcessProjectFile || + myProcessWorkspaceFile || + myProcessRunConfigurations || + !myModulesFilesToProcess.isEmpty() || + myConverter.isConversionNeeded(); } public boolean isModuleConversionNeeded(File moduleFile) throws CannotConvertException { diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java index 0aa9634d9045..f85c13a0c60f 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java @@ -84,6 +84,10 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom } public void disposeComponent() { + for (Trinity trinity : myRunningConfigurations) { + Disposer.dispose(trinity.first); + } + myRunningConfigurations.clear(); } public RunContentManager getContentManager() { @@ -316,6 +320,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom private void forgetRunContentDescriptor(RunContentDescriptor runContentDescriptor) { for (Trinity trinity : myRunningConfigurations) { if (trinity.getFirst() == runContentDescriptor) { + //runContentDescriptor.dispose(); myRunningConfigurations.remove(trinity); return; } diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 3693efbc1938..7c6475fc4610 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -33,6 +33,7 @@ import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.Disposable; import com.intellij.openapi.MnemonicHelper; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; @@ -292,21 +293,36 @@ public class FileStructurePopup implements Disposable { } IdeFocusManager.getInstance(myProject).requestFocus(myTree, true); - myFilteringStructure.rebuild(); - myAbstractTreeBuilder.queueUpdate().doWhenDone(new Runnable() { + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - myTreeHasBuilt.setDone(); - //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { + final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock(); + try { + myFilteringStructure.rebuild(); + } + finally { + token.finish(); + } + + myAbstractTreeBuilder.queueUpdate().doWhenDone(new Runnable() { @Override public void run() { - selectPsiElement(myInitialPsiElement); + myTreeHasBuilt.setDone(); + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + selectPsiElement(myInitialPsiElement); + } + }); } }); + installUpdater(); } }); + } + private void installUpdater() { if (!ApplicationManager.getApplication().isUnitTestMode()) { final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myPopup); alarm.addRequest(new Runnable() { @@ -330,24 +346,26 @@ public class FileStructurePopup implements Disposable { myAbstractTreeBuilder.refilter(null, false, false).doWhenProcessed(new Runnable() { @Override public void run() { - myTree.repaint(); - if (isBackspace && handleBackspace(filter)) { - return; - } - if (myFilteringStructure.getRootElement().getChildren().length == 0) { - for (JCheckBox box : myCheckBoxes.values()) { - if (!box.isSelected()) { - myAutoClicked.add(box); - myTriggeredCheckboxes.add(0, Pair.create(filter, box)); - box.doClick(); - filter = ""; - break; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + myTree.repaint(); + if (isBackspace && handleBackspace(filter)) { + return; + } + if (myFilteringStructure.getRootElement().getChildren().length == 0) { + for (JCheckBox box : myCheckBoxes.values()) { + if (!box.isSelected()) { + myAutoClicked.add(box); + myTriggeredCheckboxes.add(0, Pair.create(filter, box)); + box.doClick(); + filter = ""; + break; + } + } } } - } - //if (mySpeedSearch.isPopupActive()) { - // mySpeedSearch.refreshSelection(); - //} + }); } }); } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java index ade47afc2909..c16a0b0dd5ca 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java @@ -131,8 +131,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe IndexInfrastructure.getStorageFile(indexKey), extension.getKeyDescriptor(), new StubIdExternalizer(), - extension.getCacheSize(), - extension.isKeyHighlySelective() + extension.getCacheSize() ); final MemoryIndexStorage memStorage = new MemoryIndexStorage(storage); myIndices.put(indexKey, new MyIndex(memStorage)); diff --git a/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java b/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java index 8654a04850af..a1ebefe65387 100644 --- a/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java +++ b/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java @@ -80,6 +80,11 @@ public class ReplacePromptDialog extends DialogWrapper { return null; } + @Override + protected String getDimensionServiceKey() { + return "ReplaceDuplicatesPrompt"; + } + private class DoAction extends AbstractAction { private final int myExitCode; diff --git a/platform/lvcs-impl/src/com/intellij/history/core/ChangeListStorageImpl.java b/platform/lvcs-impl/src/com/intellij/history/core/ChangeListStorageImpl.java index bf43ffde4785..e8d14a945a5c 100644 --- a/platform/lvcs-impl/src/com/intellij/history/core/ChangeListStorageImpl.java +++ b/platform/lvcs-impl/src/com/intellij/history/core/ChangeListStorageImpl.java @@ -28,7 +28,6 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.newvfs.ManagingFS; -import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.util.Consumer; import com.intellij.util.io.storage.AbstractStorage; import gnu.trove.TIntHashSet; @@ -87,7 +86,7 @@ public class ChangeListStorageImpl implements ChangeListStorage { } private static long getVFSTimestamp() { - return ((PersistentFS)ManagingFS.getInstance()).getCreationTimestamp(); + return ManagingFS.getInstance().getCreationTimestamp(); } private void handleError(Throwable e, @Nullable String message) { @@ -125,11 +124,10 @@ public class ChangeListStorageImpl implements ChangeListStorage { public static void notifyUser(String message) { final String logFile = PathManager.getLogPath(); - String createIssuePart = "
" + + /*String createIssuePart = "
" + "
" + "Please attach log files from " + logFile + "
" + - "to the YouTrack issue"; - + "to the YouTrack issue";*/ Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Local History is broken", message /*+ createIssuePart*/, diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/ManagingFS.java b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/ManagingFS.java index 639d9309b607..fed0b18ecbb8 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/ManagingFS.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/ManagingFS.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -51,6 +51,8 @@ public abstract class ManagingFS implements FileSystemInterface, FileSystemPersi public abstract int getFilesystemModificationCount(); + public abstract long getCreationTimestamp(); + public abstract boolean areChildrenLoaded(@NotNull VirtualFile dir); public abstract boolean wereChildrenAccessed(@NotNull VirtualFile dir); @@ -65,7 +67,6 @@ public abstract class ManagingFS implements FileSystemInterface, FileSystemPersi @NotNull public abstract VirtualFile[] getRoots(@NotNull NewVirtualFileSystem fs); - @NotNull public abstract VirtualFile[] getLocalRoots(); diff --git a/platform/platform-impl/src/com/intellij/designer/model/Property.java b/platform/platform-impl/src/com/intellij/designer/model/Property.java index f15ecff33e07..ba6b21a50b14 100644 --- a/platform/platform-impl/src/com/intellij/designer/model/Property.java +++ b/platform/platform-impl/src/com/intellij/designer/model/Property.java @@ -89,8 +89,18 @@ public abstract class Property { public void setValue(@NotNull T container, @Nullable Object value) throws Exception { } + public final boolean isRecursiveDefault(@NotNull T container) throws Exception { + for (Property child : getChildren(container)) { + boolean isDefault = child.isRecursiveDefault(container); + if (!isDefault) { + return false; + } + } + return isDefaultValue(container); + } + public boolean isDefaultValue(@NotNull T container) throws Exception { - return false; + return true; } public void setDefaultValue(@NotNull T container) throws Exception { @@ -144,6 +154,10 @@ public abstract class Property { myDeprecated = deprecated; } + public boolean showAsDefault(@NotNull T container) throws Exception { + return isRecursiveDefault(container); + } + @NotNull public abstract PropertyRenderer getRenderer(); diff --git a/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java b/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java index 8a74423f0c20..c9eb603e37c3 100644 --- a/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java +++ b/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java @@ -200,7 +200,7 @@ public abstract class PropertyTable extends JBTable { @Override public void run() throws Exception { for (PropertiesContainer component : myContainers) { - if (!property.isDefaultValue(component)) { + if (!property.isRecursiveDefault(component)) { property.setDefaultValue(component); } } @@ -427,16 +427,16 @@ public abstract class PropertyTable extends JBTable { } } - private void fillProperties(PropertiesContainer component, List properties) { - for (Property property : component.getProperties()) { - addProperty(component, property, properties); + private void fillProperties(PropertiesContainer container, List properties) { + for (Property property : container.getProperties()) { + addProperty(container, property, properties); } } - private void addProperty(PropertiesContainer component, Property property, List properties) { + private void addProperty(PropertiesContainer container, Property property, List properties) { if (property.isExpert() && !myShowExpertProperties) { try { - if (property.isDefaultValue(component)) { + if (property.isRecursiveDefault(container)) { return; } } @@ -449,7 +449,7 @@ public abstract class PropertyTable extends JBTable { if (isExpanded(property)) { for (Property child : getChildren(property)) { - addProperty(component, child, properties); + addProperty(container, child, properties); } } } @@ -557,7 +557,7 @@ public abstract class PropertyTable extends JBTable { public boolean isDefault(Property property) throws Exception { for (PropertiesContainer component : myContainers) { - if (!property.isDefaultValue(component)) { + if (!property.isRecursiveDefault(component)) { return false; } } @@ -1142,7 +1142,12 @@ public abstract class PropertyTable extends JBTable { boolean isDefault = true; try { - isDefault = isDefault(property); + for (PropertiesContainer container : myContainers) { + if (!property.showAsDefault(container)) { + isDefault = false; + break; + } + } } catch (Exception e) { LOG.debug(e); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java index 3a6286e33fcb..a6dae5db4cb3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java @@ -136,7 +136,7 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap FileDocumentManager.getInstance().saveAllDocuments(); } }); - ((PersistentFS)ManagingFS.getInstance()).clearIdCache(); + PersistentFS.getInstance().clearIdCache(); for (VirtualFile root : ManagingFS.getInstance().getRoots(this)) { if (root instanceof VirtualDirectoryImpl) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index ac29b49eb1c7..cf394f3ab525 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -69,7 +69,10 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { // guarded by this private Object myChildren; // Either Map or VFile[] - public VirtualDirectoryImpl(@NotNull String name, final VirtualDirectoryImpl parent, @NotNull NewVirtualFileSystem fs, final int id) { + public VirtualDirectoryImpl(@NotNull final String name, + @Nullable final VirtualDirectoryImpl parent, + @NotNull final NewVirtualFileSystem fs, + final int id) { super(name, parent, id); myFS = fs; } @@ -151,7 +154,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { synchronized (this) { // do not extract getId outside the synchronized block since it will cause a concurrency problem. - int id = PersistentFS.getId(this, name, delegate); + int id = ourPersistence.getId(this, name, delegate); if (id > 0) { // maybe another doFindChild() sneaked in the middle VirtualFileSystemEntry lastTry = map.get(name); @@ -171,7 +174,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { public VirtualFileSystemEntry createChild(@NotNull String name, int id) { final VirtualFileSystemEntry child; final NewVirtualFileSystem fs = getFileSystem(); - if (PersistentFS.isDirectory(id)) { + if (ourPersistence.isDirectory(id)) { child = new VirtualDirectoryImpl(name, this, fs, id); } else { @@ -379,8 +382,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { return Arrays.asList(getChildren()); } - final String[] names = PersistentFS.listPersisted(this); - NewVirtualFileSystem delegate = PersistentFS.replaceWithNativeFS(getFileSystem()); + final String[] names = ourPersistence.listPersisted(this); + final NewVirtualFileSystem delegate = PersistentFS.replaceWithNativeFS(getFileSystem()); for (String name : names) { findChild(name, false, false, delegate); } @@ -397,7 +400,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { return children; } - Pair pair = PersistentFS.listAll(this); + Pair pair = ourPersistence.listAll(this); final int[] childrenIds = pair.second; if (childrenIds.length == 0) { children = EMPTY_ARRAY; @@ -481,8 +484,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { private Map asMap() { Object children = myChildren; if (children instanceof Map) { - //noinspection unchecked - return (Map)children; + @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) + final Map map = (Map)children; + return map; } return null; } @@ -495,8 +499,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { myChildren = map; } else { - //noinspection unchecked - map = (Map)myChildren; + @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) + final Map aMap = (Map)myChildren; + map = aMap; } return map; @@ -573,6 +578,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @TestOnly public synchronized void cleanupCachedChildren(@NotNull Set survivors) { + assert ApplicationManager.getApplication().isUnitTestMode(); if (survivors.contains(this)) { for (VirtualFile file : getCachedChildren()) { if (file instanceof VirtualDirectoryImpl) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java index 56a28bf833db..deb73dbee818 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java @@ -26,7 +26,6 @@ import com.intellij.openapi.vfs.VfsBundle; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.openapi.vfs.encoding.EncodingRegistry; -import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.util.io.IOUtil; @@ -45,7 +44,7 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile { private static final Key SYMLINK_TARGET = Key.create("SYMLINK_TARGET"); public static final VirtualFileSystemEntry[] EMPTY_ARRAY = new VirtualFileSystemEntry[0]; - protected static final PersistentFS ourPersistence = (PersistentFS)ManagingFS.getInstance(); + protected static final PersistentFS ourPersistence = PersistentFS.getInstance(); private static final byte DIRTY_FLAG = 0x01; private static final byte HAS_SYMLINK_FLAG = 0x02; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java index b949be2a7c49..00583c3a05b6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java @@ -15,1165 +15,76 @@ */ package com.intellij.openapi.vfs.newvfs.persistent; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.application.ex.ApplicationEx; -import com.intellij.openapi.components.ApplicationComponent; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.ShutDownTracker; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.*; -import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.win32.Win32LocalFileSystem; -import com.intellij.openapi.vfs.newvfs.*; -import com.intellij.openapi.vfs.newvfs.events.*; -import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; -import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; -import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.StripedLockIntObjectConcurrentHashMap; -import com.intellij.util.io.ReplicatorInputStream; -import com.intellij.util.messages.MessageBus; -import gnu.trove.THashMap; -import gnu.trove.TIntHashSet; -import gnu.trove.TIntObjectHashMap; -import org.jetbrains.annotations.NonNls; +import com.intellij.openapi.vfs.newvfs.ManagingFS; +import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; -import java.io.*; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; +import java.io.IOException; -/** - * @author max - */ -public class PersistentFS extends ManagingFS implements ApplicationComponent { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.persistent.PersistentFS"); - - private static final int CHILDREN_CACHED_FLAG = 0x01; +public abstract class PersistentFS extends ManagingFS { + static final int CHILDREN_CACHED_FLAG = 0x01; static final int IS_DIRECTORY_FLAG = 0x02; - private static final int IS_READ_ONLY = 0x04; - private static final int MUST_RELOAD_CONTENT = 0x08; - private static final int IS_SYMLINK = 0x10; - private static final int IS_SPECIAL = 0x20; + static final int IS_READ_ONLY = 0x04; + static final int MUST_RELOAD_CONTENT = 0x08; + static final int IS_SYMLINK = 0x10; + static final int IS_SPECIAL = 0x20; static final int ALL_VALID_FLAGS = CHILDREN_CACHED_FLAG | IS_DIRECTORY_FLAG | IS_READ_ONLY | MUST_RELOAD_CONTENT | IS_SYMLINK | IS_SPECIAL; - private final MessageBus myEventsBus; - - @NotNull private final Map myRoots = new THashMap(FileUtil.PATH_HASHING_STRATEGY); - @NotNull private final TIntObjectHashMap myRootsById = new TIntObjectHashMap(); - @Nullable private VirtualFileSystemEntry myFakeRoot; - @NotNull private final Object INPUT_LOCK = new Object(); - - public PersistentFS(MessageBus bus) { - myEventsBus = bus; - - ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { - @Override - public void run() { - performShutdown(); - } - }); + @SuppressWarnings("MethodOverridesStaticMethodOfSuperclass") + public static PersistentFS getInstance() { + return (PersistentFS)ManagingFS.getInstance(); } - @Override - public void disposeComponent() { - performShutdown(); - } - - @NotNull private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(Boolean.FALSE); - private void performShutdown() { - if (!myShutdownPerformed.getAndSet(Boolean.TRUE)) { - LOG.info("VFS dispose started"); - FSRecords.dispose(); - LOG.info("VFS dispose completed"); - } - } - - @Override - @NonNls - @NotNull - public String getComponentName() { - return "app.component.PersistentFS"; - } - - @Override - public void initComponent() { - FSRecords.connect(); - } - - @Override - public boolean areChildrenLoaded(@NotNull final VirtualFile dir) { - return areChildrenLoaded(getFileId(dir)); - } - - public long getCreationTimestamp() { - return FSRecords.getCreationTimestamp(); - } + public abstract void clearIdCache(); @NotNull - private static NewVirtualFileSystem getDelegate(@NotNull VirtualFile file) { - return (NewVirtualFileSystem)file.getFileSystem(); - } - - @Override - public boolean wereChildrenAccessed(@NotNull final VirtualFile dir) { - return FSRecords.wereChildrenAccessed(getFileId(dir)); - } - - @Override - @NotNull - public String[] list(@NotNull final VirtualFile file) { - int id = getFileId(file); - int[] childrenIds = FSRecords.list(id); - String[] names = listPersisted(childrenIds); - if (areChildrenLoaded(id)) { - return names; - } - Pair pair = persistAllChildren(file, id, Pair.create(names, childrenIds)); - return pair.first; - } + public abstract String[] listPersisted(@NotNull VirtualFile parent); @NotNull - public static String[] listPersisted(@NotNull VirtualFile file) { - return listPersisted(FSRecords.list(getFileId(file))); - } + public abstract Pair listAll(@NotNull VirtualFile parent); - @NotNull - private static String[] listPersisted(@NotNull int[] childrenIds) { - String[] names = ArrayUtil.newStringArray(childrenIds.length); - for (int i = 0; i < childrenIds.length; i++) { - names[i] = FSRecords.getName(childrenIds[i]); - } - return names; - } + public abstract int getId(@NotNull VirtualFile parent, @NotNull String childName, @NotNull NewVirtualFileSystem delegate); - @NotNull - private static Pair persistAllChildren(@NotNull VirtualFile file, int id, @NotNull Pair current) { - String[] currentNames = current.first; - int[] currentIds = current.second; + public abstract String getName(int id); - NewVirtualFileSystem fs = replaceWithNativeFS(getDelegate(file)); - String[] delegateNames = VfsUtil.filterNames(fs.list(file)); - if (delegateNames.length == 0 && currentNames.length > 0) { - return current; - } + public abstract boolean isDirectory(int id); - final String[] names; - if (currentNames.length == 0) { - names = delegateNames; - } - else { - Set allNamesSet = new LinkedHashSet((currentNames.length + delegateNames.length) * 2); - ContainerUtil.addAll(allNamesSet, currentNames); - ContainerUtil.addAll(allNamesSet, delegateNames); - names = ArrayUtil.toStringArray(allNamesSet); - } - - final int[] childrenIds = ArrayUtil.newIntArray(names.length); - - for (int i = 0; i < names.length; i++) { - final String name = names[i]; - int idx = ArrayUtil.indexOf(currentNames, name); - if (idx >= 0) { - childrenIds[i] = currentIds[idx]; - } - else { - final FakeVirtualFile child = new FakeVirtualFile(file, name); - final FileAttributes attributes = fs.getAttributes(child); - assert attributes != null : fs + ": " + child; - final int childId = createAndCopyRecord(fs, child, id, attributes); - childrenIds[i] = childId; - } - } - - FSRecords.updateList(id, childrenIds); - int flags = FSRecords.getFlags(id); - FSRecords.setFlags(id, flags | CHILDREN_CACHED_FLAG, true); - - return Pair.create(names, childrenIds); - } - - @NotNull - public static int[] listIds(@NotNull VirtualFile parent) { - final int parentId = getFileId(parent); - - int[] ids = FSRecords.list(parentId); - if (!areChildrenLoaded(parentId)) { - String[] names = listPersisted(ids); - Pair pair = persistAllChildren(parent, parentId, Pair.create(names, ids)); - return pair.second; - } - - return ids; - } - - @NotNull - public static Pair listAll(@NotNull VirtualFile parent) { - final int parentId = getFileId(parent); - - Pair pair = FSRecords.listAll(parentId); - if (!areChildrenLoaded(parentId)) { - return persistAllChildren(parent, parentId, pair); - } - - return pair; - } - - - private static boolean areChildrenLoaded(final int parentId) { - final int mask = CHILDREN_CACHED_FLAG; - return (FSRecords.getFlags(parentId) & mask) != 0; - } - - @Override - @Nullable - public DataInputStream readAttribute(@NotNull final VirtualFile file, @NotNull final FileAttribute att) { - return FSRecords.readAttribute(getFileId(file), att.getId()); - } - - @Override - @NotNull - public DataOutputStream writeAttribute(@NotNull final VirtualFile file, @NotNull final FileAttribute att) { - return FSRecords.writeAttribute(getFileId(file), att.getId(), att.isFixedSize()); - } + public abstract long getLengthNoFollow(@NotNull VirtualFile file); @Nullable - private static DataInputStream readContent(@NotNull VirtualFile file) { - return FSRecords.readContent(getFileId(file)); - } + public abstract NewVirtualFile findFileByIdIfCached(int id); - @Nullable - private static DataInputStream readContentById(int contentId) { - return FSRecords.readContentById(contentId); - } + public abstract int storeUnlinkedContent(@NotNull byte[] bytes); @NotNull - private static DataOutputStream writeContent(@NotNull VirtualFile file, boolean readOnly) { - return FSRecords.writeContent(getFileId(file), readOnly); - } - - private static void writeContent(@NotNull VirtualFile file, ByteSequence content, boolean readOnly) throws IOException { - FSRecords.writeContent(getFileId(file), content, readOnly); - } - - public int storeUnlinkedContent(byte[] bytes) { - return FSRecords.storeUnlinkedContent(bytes); - } - - @Override - public int getModificationCount(@NotNull final VirtualFile file) { - final int id = getFileId(file); - return FSRecords.getModCount(id); - } - - @Override - public int getCheapFileSystemModificationCount() { - return FSRecords.getLocalModCount(); - } - - @Override - public int getFilesystemModificationCount() { - return FSRecords.getModCount(); - } - - private static boolean copyRecordFromDelegateFS(final int id, - final int parentId, - @NotNull VirtualFile file, - @NotNull NewVirtualFileSystem fs, - @NotNull FileAttributes attributes) { - String name = file.getName(); - if (!name.isEmpty()) { - if (namesEqual(fs, name, FSRecords.getName(id))) return false; // TODO: Handle root attributes change. - } - else { - if (areChildrenLoaded(id)) return false; // TODO: hack - } - - FSRecords.setParent(id, parentId); - FSRecords.setName(id, name); - - FSRecords.setTimestamp(id, attributes.lastModified); - FSRecords.setLength(id, attributes.isDirectory() ? -1L : attributes.length); - - FSRecords.setFlags(id, (attributes.isDirectory() ? IS_DIRECTORY_FLAG : 0) | - (attributes.isWritable() ? 0 : IS_READ_ONLY) | - (attributes.isSymLink() ? IS_SYMLINK : 0) | - (attributes.isSpecial() ? IS_SPECIAL : 0), true); - - return true; - } - - @Override - public boolean isDirectory(@NotNull final VirtualFile file) { - final int id = getFileId(file); - return isDirectory(id); - } - - public static boolean isDirectory(final int id) { - assert id > 0; - return (FSRecords.getFlags(id) & IS_DIRECTORY_FLAG) != 0; - } - - public static boolean isSymLink(final int id) { - assert id > 0; - return (FSRecords.getFlags(id) & IS_SYMLINK) != 0; - } - - private static int getParent(final int id) { - assert id > 0; - return FSRecords.getParent(id); - } - - private static boolean namesEqual(@NotNull VirtualFileSystem fs, @NotNull String n1, String n2) { - return ((NewVirtualFileSystem)fs).isCaseSensitive() ? n1.equals(n2) : n1.equalsIgnoreCase(n2); - } - - @Override - public boolean exists(@NotNull final VirtualFile fileOrDirectory) { - return ((VirtualFileWithId)fileOrDirectory).getId() > 0; - } - - @Override - public long getTimeStamp(@NotNull final VirtualFile file) { - final int id = getFileId(file); - return FSRecords.getTimestamp(id); - } - - @Override - public void setTimeStamp(@NotNull final VirtualFile file, final long modStamp) throws IOException { - final int id = getFileId(file); - FSRecords.setTimestamp(id, modStamp); - getDelegate(file).setTimeStamp(file, modStamp); - } - - private static int getFileId(@NotNull VirtualFile file) { - final int id = ((VirtualFileWithId)file).getId(); - if (id <= 0) { - throw new InvalidVirtualFileAccessException(file); - } - return id; - } - - @Override - public boolean isSymLink(@NotNull VirtualFile file) { - return (FSRecords.getFlags(getFileId(file)) & IS_SYMLINK) != 0; - } - - @Override - public String resolveSymLink(@NotNull VirtualFile file) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isSpecialFile(@NotNull VirtualFile file) { - return (FSRecords.getFlags(getFileId(file)) & IS_SPECIAL) != 0; - } - - @Override - public boolean isWritable(@NotNull final VirtualFile file) { - return (FSRecords.getFlags(getFileId(file)) & IS_READ_ONLY) == 0; - } - - @Override - public void setWritable(@NotNull final VirtualFile file, final boolean writableFlag) throws IOException { - getDelegate(file).setWritable(file, writableFlag); - processEvent(new VFilePropertyChangeEvent(this, file, VirtualFile.PROP_WRITABLE, isWritable(file), writableFlag, false)); - } - - public static int getId(@NotNull final VirtualFile parent, @NotNull final String childName, @NotNull NewVirtualFileSystem delegate) { - final int parentId = getFileId(parent); - - final int[] children = FSRecords.list(parentId); - for (final int childId : children) { - if (namesEqual(delegate, childName, FSRecords.getName(childId))) return childId; - } - - final VirtualFile fake = new FakeVirtualFile(parent, childName); - final FileAttributes attributes = delegate.getAttributes(fake); - if (attributes != null) { - final int child = createAndCopyRecord(delegate, fake, parentId, attributes); - FSRecords.updateList(parentId, ArrayUtil.append(children, child)); - return child; - } - - return 0; - } - - @Override - public long getLength(@NotNull final VirtualFile file) { - final VirtualFile canonicalFile = file.getCanonicalFile(); - return canonicalFile == null ? 0 : getLengthNoFollow(canonicalFile); - } - - @SuppressWarnings("MethodMayBeStatic") - public long getLengthNoFollow(@NotNull final VirtualFile file) { - final int id = getFileId(file); - - long len = FSRecords.getLength(id); - if (len == -1) { - len = (int)getDelegate(file).getLength(file); - FSRecords.setLength(id, len); - } - - return len; - } - - @Override - public VirtualFile copyFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final VirtualFile newParent, @NotNull final String copyName) - throws IOException { - getDelegate(file).copyFile(requestor, file, newParent, copyName); - processEvent(new VFileCopyEvent(requestor, file, newParent, copyName)); - - final VirtualFile child = newParent.findChild(copyName); - if (child == null) { - throw new IOException("Cannot create child"); - } - return child; - } - - @Override - public VirtualFile createChildDirectory(final Object requestor, @NotNull final VirtualFile parent, @NotNull final String dir) throws IOException { - getDelegate(parent).createChildDirectory(requestor, parent, dir); - processEvent(new VFileCreateEvent(requestor, parent, dir, true, false)); - - final VirtualFile child = parent.findChild(dir); - if (child == null) { - throw new IOException("Cannot create child directory '" + dir + "' at " + parent.getPath()); - } - return child; - } - - @Override - public VirtualFile createChildFile(final Object requestor, @NotNull final VirtualFile parent, @NotNull final String file) throws IOException { - getDelegate(parent).createChildFile(requestor, parent, file); - processEvent(new VFileCreateEvent(requestor, parent, file, false, false)); - - final VirtualFile child = parent.findChild(file); - if (child == null) { - throw new IOException("Cannot create child file '" + file + "' at " + parent.getPath()); - } - return child; - } - - @Override - public void deleteFile(final Object requestor, @NotNull final VirtualFile file) throws IOException { - final NewVirtualFileSystem delegate = getDelegate(file); - delegate.deleteFile(requestor, file); - - if (!delegate.exists(file)) { - processEvent(new VFileDeleteEvent(requestor, file, false)); - } - } - - @Override - public void renameFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final String newName) throws IOException { - getDelegate(file).renameFile(requestor, file, newName); - processEvent(new VFilePropertyChangeEvent(requestor, file, VirtualFile.PROP_NAME, file.getName(), newName, false)); - } - - @Override - @NotNull - public byte[] contentsToByteArray(@NotNull final VirtualFile file) throws IOException { - return contentsToByteArray(file, true); - } + public abstract byte[] contentsToByteArray(int contentId) throws IOException; @NotNull - public byte[] contentsToByteArray(@NotNull final VirtualFile file, boolean cacheContent) throws IOException { - final VirtualFile canonicalFile = getCanonicalFile(file); + public abstract byte[] contentsToByteArray(@NotNull VirtualFile file, boolean cacheContent) throws IOException; - InputStream contentStream = null; - boolean reloadFromDelegate; - synchronized (INPUT_LOCK) { - reloadFromDelegate = mustReloadContent(canonicalFile) || (contentStream = readContent(canonicalFile)) == null; - } + public abstract int acquireContent(@NotNull VirtualFile file); - if (reloadFromDelegate) { - final NewVirtualFileSystem delegate = getDelegate(canonicalFile); - final byte[] content = delegate.contentsToByteArray(canonicalFile); - FSRecords.setLength(getFileId(canonicalFile), content.length); + public abstract void releaseContent(int contentId); - ApplicationEx application = (ApplicationEx)ApplicationManager.getApplication(); - // we should cache every local files content - // because the local history feature is currently depends on this cache, - // perforce offline mode as well - if ((!delegate.isReadOnly() || - // do not cache archive content unless asked - (cacheContent && !application.isInternal() && !application.isUnitTestMode())) && - content.length <= PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD) { - synchronized (INPUT_LOCK) { - writeContent(canonicalFile, new ByteSequence(content), delegate.isReadOnly()); - setFlag(canonicalFile, MUST_RELOAD_CONTENT, false); - } - } - - return content; - } - else { - try { - final int length = (int)canonicalFile.getLength(); - assert length >= 0 : canonicalFile; - return FileUtil.loadBytes(contentStream, length); - } - catch (IOException e) { - throw FSRecords.handleError(e); - } - } - } + public abstract int getCurrentContentId(@NotNull VirtualFile file); @NotNull - public byte[] contentsToByteArray(int contentId) throws IOException { - return FileUtil.loadBytes(readContentById(contentId)); - } - - @Override - @NotNull - public InputStream getInputStream(@NotNull final VirtualFile file) throws IOException { - final VirtualFile canonicalFile = getCanonicalFile(file); - synchronized (INPUT_LOCK) { - InputStream contentStream; - if (mustReloadContent(canonicalFile) || (contentStream = readContent(canonicalFile)) == null) { - final NewVirtualFileSystem delegate = getDelegate(canonicalFile); - final long len = delegate.getLength(canonicalFile); - FSRecords.setLength(getFileId(canonicalFile), len); - final InputStream nativeStream = delegate.getInputStream(canonicalFile); - - if (len > PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD) return nativeStream; - return createReplicator(canonicalFile, nativeStream, len, delegate.isReadOnly()); - } - else { - return contentStream; - } - } - } - - @NotNull - private static VirtualFile getCanonicalFile(@NotNull final VirtualFile file) throws IOException { - final VirtualFile canonicalFile = file.getCanonicalFile(); - if (canonicalFile == null) { - throw new IOException("Broken link: " + file); - } - return canonicalFile; - } - - private InputStream createReplicator(@NotNull final VirtualFile file, final InputStream nativeStream, final long fileLength, final boolean readOnly) - throws IOException { - if (nativeStream instanceof BufferExposingByteArrayInputStream) { - // optimization - BufferExposingByteArrayInputStream byteStream = (BufferExposingByteArrayInputStream )nativeStream; - byte[] bytes = byteStream.getInternalBuffer(); - storeContentToStorage(fileLength, file, readOnly, bytes, bytes.length); - return nativeStream; - } - final BufferExposingByteArrayOutputStream cache = new BufferExposingByteArrayOutputStream((int)fileLength); - return new ReplicatorInputStream(nativeStream, cache) { - @Override - public void close() throws IOException { - super.close(); - storeContentToStorage(fileLength, file, readOnly, cache.getInternalBuffer(), cache.size()); - } - }; - } - - private void storeContentToStorage(long fileLength, - @NotNull VirtualFile file, - boolean readOnly, @NotNull byte[] bytes, int bytesLength) - throws IOException { - synchronized (INPUT_LOCK) { - if (bytesLength == fileLength) { - writeContent(file, new ByteSequence(bytes, 0, bytesLength), readOnly); - setFlag(file, MUST_RELOAD_CONTENT, false); - } - else { - setFlag(file, MUST_RELOAD_CONTENT, true); - } - } - } - - private static boolean mustReloadContent(@NotNull VirtualFile file) { - return checkFlag(file, MUST_RELOAD_CONTENT) || FSRecords.getLength(getFileId(file)) == -1L; - } - - @Override - @NotNull - public OutputStream getOutputStream(@NotNull final VirtualFile file, - final Object requestor, - final long modStamp, - final long timeStamp) throws IOException { - final VirtualFile canonicalFile = getCanonicalFile(file); - - final VFileContentChangeEvent event = new VFileContentChangeEvent(requestor, canonicalFile, canonicalFile.getModificationStamp(), modStamp, false); - - final List events = Collections.singletonList(event); - - final BulkFileListener publisher = myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES); - publisher.before(events); - - return new ByteArrayOutputStream() { - private boolean closed; // protection against user calling .close() twice - @Override - public void close() throws IOException { - if (closed) return; - super.close(); - - NewVirtualFileSystem delegate = getDelegate(canonicalFile); - OutputStream ioFileStream = delegate.getOutputStream(canonicalFile, requestor, modStamp, timeStamp); - // com.intellij.openapi.vfs.newvfs.persistent.FSRecords.ContentOutputStream already buffered, no need to wrap in BufferedStream - OutputStream persistenceStream = writeContent(canonicalFile, delegate.isReadOnly()); - - try { - persistenceStream.write(buf, 0, count); - } - finally { - try { - ioFileStream.write(buf, 0, count); - } - finally { - closed = true; - persistenceStream.close(); - ioFileStream.close(); - executeTouch(canonicalFile, false, event.getModificationStamp()); - publisher.after(events); - } - } - } - }; - } - - public int acquireContent(@NotNull VirtualFile file) { - return FSRecords.acquireFileContent(getFileId(file)); - } - - public void releaseContent(int contentId) { - FSRecords.releaseContent(contentId); - } - - public int getCurrentContentId(@NotNull VirtualFile file) { - return FSRecords.getContentId(getFileId(file)); - } - - @Override - public void moveFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final VirtualFile newParent) throws IOException { - getDelegate(file).moveFile(requestor, file, newParent); - processEvent(new VFileMoveEvent(requestor, file, newParent)); - } - - private void processEvent(@NotNull VFileEvent event) { - processEvents(Collections.singletonList(event)); - } - - private static class EventWrapper { - private final VFileDeleteEvent event; - private final int id; - - private EventWrapper(final VFileDeleteEvent event, final int id) { - this.event = event; - this.id = id; - } - } - - @NotNull private static final Comparator DEPTH_COMPARATOR = new Comparator() { - @Override - public int compare(@NotNull final EventWrapper o1, @NotNull final EventWrapper o2) { - return o1.event.getFileDepth() - o2.event.getFileDepth(); - } - }; - - @NotNull - private static List validateEvents(@NotNull List events) { - final List deletionEvents = ContainerUtil.newArrayList(); - for (int i = 0, size = events.size(); i < size; i++) { - final VFileEvent event = events.get(i); - if (event instanceof VFileDeleteEvent && event.isValid()) { - deletionEvents.add(new EventWrapper((VFileDeleteEvent)event, i)); - } - } - - ContainerUtil.quickSort(deletionEvents, DEPTH_COMPARATOR); - - final TIntHashSet invalidIDs = new TIntHashSet(deletionEvents.size()); - final List dirsToBeDeleted = new ArrayList(); - nextEvent: - for (EventWrapper wrapper : deletionEvents) { - final VirtualFile candidate = wrapper.event.getFile(); - for (VirtualFile file : dirsToBeDeleted) { - if (VfsUtilCore.isAncestor(file, candidate, false)) { - invalidIDs.add(wrapper.id); - continue nextEvent; - } - } - - if (candidate.isDirectory()) { - dirsToBeDeleted.add(candidate); - } - } - - final List filtered = ContainerUtil.newArrayListWithCapacity(events.size() - invalidIDs.size()); - for (int i = 0, size = events.size(); i < size; i++) { - final VFileEvent event = events.get(i); - if (event.isValid() && !(event instanceof VFileDeleteEvent && invalidIDs.contains(i))) { - filtered.add(event); - } - } - return filtered; - } - - @Override - public void processEvents(@NotNull List events) { - ApplicationManager.getApplication().assertWriteAccessAllowed(); - - events = validateEvents(events); - - BulkFileListener publisher = myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES); - publisher.before(events); - for (VFileEvent event : events) { - applyEvent(event); - } - publisher.after(events); - } - - @NotNull public static final Object LOCK = new Object(); - - @Override - @Nullable - public VirtualFileSystemEntry findRoot(@NotNull String basePath, @NotNull NewVirtualFileSystem fs) { // TODO: read/write locks instead of synchronized - synchronized (LOCK) { - String rootUrl = fs.getProtocol() + "://" + basePath; - VirtualFileSystemEntry root = myRoots.get(rootUrl); - if (root == null && basePath.isEmpty()) { - root = myFakeRoot; - } - if (root == null) { - try { - final int rootId = FSRecords.findRootRecord(rootUrl); - if (basePath.isEmpty()) { - // fake root for windows - root = new VirtualDirectoryImpl("", null, fs, rootId) { - @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod") - @Override - @NotNull - public VirtualFile[] getChildren() { - return getRoots(getFileSystem()); - } - - @Override - public VirtualFileSystemEntry findChild(@NotNull String name) { - if (name.isEmpty()) return null; - return findRoot(name, getFileSystem()); - } - }; - } - else { - if (fs instanceof JarFileSystem) { - // optimization: for jar roots do not store base path in the myName field, use local FS file's getPath() - String parentPath = basePath.substring(0, basePath.indexOf(JarFileSystem.JAR_SEPARATOR)); - final VirtualFile parentLocalFile = LocalFileSystem.getInstance().findFileByPath(parentPath); - if (parentLocalFile == null) return null; - root = new JarRoot(fs, rootId, parentLocalFile); - } - else { - root = new VirtualDirectoryImpl(basePath, null, fs, rootId); - } - } - - final FileAttributes attributes = fs.getAttributes(root); - if (attributes == null) { - return null; - } - - final boolean newRoot = copyRecordFromDelegateFS(rootId, 0, root, fs, attributes); - if (!newRoot) { - if (attributes.lastModified != FSRecords.getTimestamp(rootId)) { - root.markDirtyRecursively(); - } - } - } - catch (IOException e) { - throw new RuntimeException(e); - } - - if (basePath.isEmpty()) { - myFakeRoot = root; - } - else { - myRoots.put(rootUrl, root); - myRootsById.put(root.getId(), root); - } - } - - return root; - } - } - - @Override - public void refresh(final boolean asynchronous) { - final NewVirtualFile[] roots; - synchronized (LOCK) { - Collection values = myRoots.values(); - roots = values.toArray(new NewVirtualFile[values.size()]); - } - - RefreshQueue.getInstance().refresh(asynchronous, true, null, roots); - } - - @Override - public void refresh(boolean asynchronous, Runnable postAction, @NotNull ModalityState modalityState) { - final NewVirtualFile[] roots; - synchronized (LOCK) { - Collection values = myRoots.values(); - roots = values.toArray(new NewVirtualFile[values.size()]); - } - - RefreshQueue.getInstance().refresh(asynchronous, true, postAction, modalityState, roots); - } - - @Override - @NotNull - public VirtualFile[] getLocalRoots() { - List roots; - synchronized (LOCK) { - roots = new ArrayList(myRoots.values()); - - final Iterator it = roots.iterator(); - while (it.hasNext()) { - NewVirtualFile file = it.next(); - if (!file.isInLocalFileSystem()) { - it.remove(); - } - } - } - - return VfsUtilCore.toVirtualFileArray(roots); - } - - //guarded by dirCacheReadLock/dirCacheWriteLock - @NotNull private final StripedLockIntObjectConcurrentHashMap myIdToDirCache = new StripedLockIntObjectConcurrentHashMap(); - - public void clearIdCache() { - myIdToDirCache.clear(); - } - - @Override - @Nullable - public NewVirtualFile findFileById(final int id) { - return _findFileById(id, false); - } - - - @Nullable - public NewVirtualFile findFileByIdIfCached(final int id) { - return _findFileById(id, true); - } - - @Nullable - private NewVirtualFile _findFileById(int id, final boolean cachedOnly) { - final NewVirtualFile cached = myIdToDirCache.get(id); - if (cached != null) { - return cached; - } - - NewVirtualFile result = doFindFile(id, cachedOnly); - - if (result != null && result.isDirectory()) { - NewVirtualFile old = myIdToDirCache.putIfAbsent(id, result); - if (old != null) result = old; - } - return result; - } - - @Nullable - private NewVirtualFile doFindFile(final int id, boolean cachedOnly) { - final int parentId = getParent(id); - if (parentId == 0) { - synchronized (LOCK) { - return myRootsById.get(id); - } - } - else { - NewVirtualFile parentFile = _findFileById(parentId, cachedOnly); - if (parentFile == null) { - return null; - } - return cachedOnly ? parentFile.findChildByIdIfCached(id) : parentFile.findChildById(id); - } - } - - @Override - @NotNull - public VirtualFile[] getRoots() { - synchronized (LOCK) { - Collection roots = myRoots.values(); - return VfsUtilCore.toVirtualFileArray(roots); - } - } - - @Override - @NotNull - public VirtualFile[] getRoots(@NotNull final NewVirtualFileSystem fs) { - List roots = new ArrayList(); - synchronized (LOCK) { - for (NewVirtualFile root : myRoots.values()) { - if (root.getFileSystem() == fs) { - roots.add(root); - } - } - } - - return VfsUtilCore.toVirtualFileArray(roots); - } - - private void applyEvent(@NotNull VFileEvent event) { - try { - if (event instanceof VFileCreateEvent) { - final VFileCreateEvent createEvent = (VFileCreateEvent)event; - executeCreateChild(createEvent.getParent(), createEvent.getChildName()); - } - else if (event instanceof VFileDeleteEvent) { - final VFileDeleteEvent deleteEvent = (VFileDeleteEvent)event; - executeDelete(deleteEvent.getFile()); - } - else if (event instanceof VFileContentChangeEvent) { - final VFileContentChangeEvent contentUpdateEvent = (VFileContentChangeEvent)event; - executeTouch(contentUpdateEvent.getFile(), contentUpdateEvent.isFromRefresh(), contentUpdateEvent.getModificationStamp()); - } - else if (event instanceof VFileCopyEvent) { - final VFileCopyEvent copyEvent = (VFileCopyEvent)event; - executeCopy(copyEvent.getFile(), copyEvent.getNewParent(), copyEvent.getNewChildName()); - } - else if (event instanceof VFileMoveEvent) { - final VFileMoveEvent moveEvent = (VFileMoveEvent)event; - executeMove(moveEvent.getFile(), moveEvent.getNewParent()); - } - else if (event instanceof VFilePropertyChangeEvent) { - final VFilePropertyChangeEvent propertyChangeEvent = (VFilePropertyChangeEvent)event; - if (VirtualFile.PROP_NAME.equals(propertyChangeEvent.getPropertyName())) { - executeRename(propertyChangeEvent.getFile(), (String)propertyChangeEvent.getNewValue()); - } - else if (VirtualFile.PROP_WRITABLE.equals(propertyChangeEvent.getPropertyName())) { - executeSetWritable(propertyChangeEvent.getFile(), ((Boolean)propertyChangeEvent.getNewValue()).booleanValue()); - } - } - } - catch (Exception e) { - // Exception applying single event should not prevent other events from applying. - LOG.error(e); - } - } - - @NotNull - @NonNls - public String toString() { - return "PersistentFS"; - } - - private static void executeCreateChild(@NotNull VirtualFile parent, @NotNull String name) { - final NewVirtualFileSystem delegate = getDelegate(parent); - final VirtualFile fake = new FakeVirtualFile(parent, name); - final FileAttributes attributes = delegate.getAttributes(fake); - if (attributes != null) { - final int parentId = getFileId(parent); - final int childId = createAndCopyRecord(delegate, fake, parentId, attributes); - appendIdToParentList(parentId, childId); - assert parent instanceof VirtualDirectoryImpl : parent; - final VirtualDirectoryImpl dir = (VirtualDirectoryImpl)parent; - dir.addChild(dir.createChild(name, childId)); - } - } - - private static int createAndCopyRecord(@NotNull NewVirtualFileSystem delegateSystem, - @NotNull VirtualFile delegateFile, - int parentId, - @NotNull FileAttributes attributes) { - final int childId = FSRecords.createRecord(); - copyRecordFromDelegateFS(childId, parentId, delegateFile, delegateSystem, attributes); - return childId; - } - - private static void appendIdToParentList(final int parentId, final int childId) { - int[] childrenList = FSRecords.list(parentId); - childrenList = ArrayUtil.append(childrenList, childId); - FSRecords.updateList(parentId, childrenList); - } - - private void executeDelete(@NotNull VirtualFile file) { - if (!file.exists()) { - LOG.error("Deleting a file, which does not exist: " + file.getPath()); - } - else { - clearIdCache(); - - final int id = getFileId(file); - - final VirtualFile parent = file.getParent(); - final int parentId = parent != null ? getFileId(parent) : 0; - - FSRecords.deleteRecordRecursively(id); - - if (parentId != 0) { - removeIdFromParentList(parentId, id, parent, file); - VirtualDirectoryImpl directory = (VirtualDirectoryImpl)file.getParent(); - assert directory != null; - - directory.removeChild(file); - } - else { - synchronized (LOCK) { - myRoots.remove(file.getUrl()); - myRootsById.remove(id); - try { - FSRecords.deleteRootRecord(id); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - invalidateSubtree(file); - } - } - - private static void invalidateSubtree(@NotNull VirtualFile file) { - final VirtualFileSystemEntry impl = (VirtualFileSystemEntry)file; - impl.invalidate(); - for (VirtualFile child : impl.getCachedChildren()) { - invalidateSubtree(child); - } - } - - private static void removeIdFromParentList(final int parentId, final int id, @NotNull VirtualFile parent, VirtualFile file) { - int[] childList = FSRecords.list(parentId); - - int index = ArrayUtil.indexOf(childList, id); - if (index == -1) { - throw new RuntimeException("Cannot find child (" + id + ")" + file - + "\n\tin (" + parentId + ")" + parent - + "\n\tactual children:" + Arrays.toString(childList)); - } - childList = ArrayUtil.remove(childList, index); - FSRecords.updateList(parentId, childList); - } - - private static void executeRename(@NotNull VirtualFile file, @NotNull final String newName) { - ((VirtualFileSystemEntry)file).setNewName(newName); - final int id = getFileId(file); - FSRecords.setName(id, newName); - } - - private static void executeSetWritable(@NotNull VirtualFile file, final boolean writableFlag) { - setFlag(file, IS_READ_ONLY, !writableFlag); - } - - private static void setFlag(@NotNull VirtualFile file, int mask, boolean value) { - setFlag(getFileId(file), mask, value); - } - - private static void setFlag(final int id, final int mask, final boolean value) { - int oldFlags = FSRecords.getFlags(id); - int flags = value ? oldFlags | mask : oldFlags & ~mask; - - if (oldFlags != flags) { - FSRecords.setFlags(id, flags, true); - } - } - - private static boolean checkFlag(@NotNull VirtualFile file, int mask) { - return (FSRecords.getFlags(getFileId(file)) & mask) != 0; - } - - private static void executeTouch(@NotNull VirtualFile file, boolean reloadContentFromDelegate, long newModificationStamp) { - if (reloadContentFromDelegate) { - setFlag(file, MUST_RELOAD_CONTENT, true); - } - - final NewVirtualFileSystem delegate = getDelegate(file); - final FileAttributes attributes = delegate.getAttributes(file); - FSRecords.setLength(getFileId(file), attributes != null ? attributes.length : DEFAULT_LENGTH); - FSRecords.setTimestamp(getFileId(file), attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP); - - ((VirtualFileSystemEntry)file).setModificationStamp(newModificationStamp); - } - - @SuppressWarnings({"UnusedDeclaration"}) - private static void executeCopy(VirtualFile from, @NotNull VirtualFile newParent, @NotNull String copyName) { - executeCreateChild(newParent, copyName); - } - - private static void executeMove(@NotNull VirtualFile file, @NotNull VirtualFile newParent) { - final int fileId = getFileId(file); - final int newParentId = getFileId(newParent); - final int oldParentId = getFileId(file.getParent()); - - removeIdFromParentList(oldParentId, fileId, file.getParent(), file); - appendIdToParentList(newParentId, fileId); - - ((VirtualFileSystemEntry)file).setParent(newParent); - FSRecords.setParent(fileId, newParentId); - } - - public String getName(final int id) { - assert id > 0; - return FSRecords.getName(id); - } - - @TestOnly - public static void cleanPersistedContents() { - try { - final int[] roots = FSRecords.listRoots(); - for (int root : roots) { - cleanPersistedContentsRecursively(root); - } - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - @TestOnly - private static void cleanPersistedContentsRecursively(int id) { - if (isDirectory(id)) { - for (int child : FSRecords.list(id)) { - cleanPersistedContentsRecursively(child); - } - } - else { - setFlag(id, MUST_RELOAD_CONTENT, true); - } - } - - @NotNull - public static NewVirtualFileSystem replaceWithNativeFS(@NotNull final NewVirtualFileSystem delegate) { + public static NewVirtualFileSystem replaceWithNativeFS(@NotNull final NewVirtualFileSystem fs) { if (SystemInfo.isWindows && - delegate.getProtocol().equals(LocalFileSystem.PROTOCOL) && + !(fs instanceof Win32LocalFileSystem) && + fs.getProtocol().equals(LocalFileSystem.PROTOCOL) && Win32LocalFileSystem.isAvailable()) { return Win32LocalFileSystem.getWin32Instance(); } - return delegate; - } - - private static class JarRoot extends VirtualDirectoryImpl { - private final VirtualFile myParentLocalFile; - - public JarRoot(@NotNull NewVirtualFileSystem fs, int rootId, @NotNull VirtualFile parentLocalFile) { - super("", null, fs, rootId); - myParentLocalFile = parentLocalFile; - } - - @NotNull - @Override - public String getName() { - return myParentLocalFile.getName(); - } - - @Override - protected Object rawName() { - return myParentLocalFile.getPath() + JarFileSystem.JAR_SEPARATOR; - } + return fs; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java new file mode 100644 index 000000000000..2c055cb0d33b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -0,0 +1,1173 @@ +/* + * 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.openapi.vfs.newvfs.persistent; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.ex.ApplicationEx; +import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.ShutDownTracker; +import com.intellij.openapi.util.io.*; +import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.newvfs.*; +import com.intellij.openapi.vfs.newvfs.events.*; +import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile; +import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; +import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.StripedLockIntObjectConcurrentHashMap; +import com.intellij.util.io.ReplicatorInputStream; +import com.intellij.util.messages.MessageBus; +import gnu.trove.THashMap; +import gnu.trove.TIntHashSet; +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +import java.io.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author max + */ +public class PersistentFSImpl extends PersistentFS implements ApplicationComponent { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.persistent.PersistentFS"); + + private final MessageBus myEventsBus; + + @NotNull private final Map myRoots = new THashMap(FileUtil.PATH_HASHING_STRATEGY); + @NotNull private final TIntObjectHashMap myRootsById = new TIntObjectHashMap(); + @Nullable private VirtualFileSystemEntry myFakeRoot; + @NotNull private final Object INPUT_LOCK = new Object(); + + public PersistentFSImpl(@NotNull final MessageBus bus) { + myEventsBus = bus; + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + @Override + public void run() { + performShutdown(); + } + }); + } + + @Override + public void disposeComponent() { + performShutdown(); + } + + @NotNull private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(Boolean.FALSE); + private void performShutdown() { + if (!myShutdownPerformed.getAndSet(Boolean.TRUE)) { + LOG.info("VFS dispose started"); + FSRecords.dispose(); + LOG.info("VFS dispose completed"); + } + } + + @Override + @NonNls + @NotNull + public String getComponentName() { + return "app.component.PersistentFS"; + } + + @Override + public void initComponent() { + FSRecords.connect(); + } + + @Override + public boolean areChildrenLoaded(@NotNull final VirtualFile dir) { + return areChildrenLoaded(getFileId(dir)); + } + + @Override + public long getCreationTimestamp() { + return FSRecords.getCreationTimestamp(); + } + + @NotNull + private static NewVirtualFileSystem getDelegate(@NotNull VirtualFile file) { + return (NewVirtualFileSystem)file.getFileSystem(); + } + + @Override + public boolean wereChildrenAccessed(@NotNull final VirtualFile dir) { + return FSRecords.wereChildrenAccessed(getFileId(dir)); + } + + @Override + @NotNull + public String[] list(@NotNull final VirtualFile file) { + int id = getFileId(file); + int[] childrenIds = FSRecords.list(id); + String[] names = listPersisted(childrenIds); + if (areChildrenLoaded(id)) { + return names; + } + Pair pair = persistAllChildren(file, id, Pair.create(names, childrenIds)); + return pair.first; + } + + @Override + @NotNull + public String[] listPersisted(@NotNull VirtualFile parent) { + return listPersisted(FSRecords.list(getFileId(parent))); + } + + @NotNull + private static String[] listPersisted(@NotNull int[] childrenIds) { + String[] names = ArrayUtil.newStringArray(childrenIds.length); + for (int i = 0; i < childrenIds.length; i++) { + names[i] = FSRecords.getName(childrenIds[i]); + } + return names; + } + + @NotNull + private static Pair persistAllChildren(@NotNull VirtualFile file, int id, @NotNull Pair current) { + String[] currentNames = current.first; + int[] currentIds = current.second; + + NewVirtualFileSystem fs = replaceWithNativeFS(getDelegate(file)); + String[] delegateNames = VfsUtil.filterNames(fs.list(file)); + if (delegateNames.length == 0 && currentNames.length > 0) { + return current; + } + + String[] names; + if (currentNames.length == 0) { + names = delegateNames; + } + else { + Set allNamesSet = new LinkedHashSet((currentNames.length + delegateNames.length) * 2); + ContainerUtil.addAll(allNamesSet, currentNames); + ContainerUtil.addAll(allNamesSet, delegateNames); + names = ArrayUtil.toStringArray(allNamesSet); + } + + int[] childrenIds = ArrayUtil.newIntArray(names.length); + + int filter = 0; + for (int i = 0; i < names.length; i++) { + final String name = names[i]; + int idx = ArrayUtil.indexOf(currentNames, name); + if (idx >= 0) { + childrenIds[i] = currentIds[idx]; + } + else { + final FakeVirtualFile child = new FakeVirtualFile(file, name); + final FileAttributes attributes = fs.getAttributes(child); + if (attributes != null) { + final int childId = createAndCopyRecord(fs, child, id, attributes); + childrenIds[i] = childId; + } + else { + childrenIds[i] = -1; + ++filter; + LOG.warn("fs=" + fs + " dir=" + file + " name=" + name + " curr=" + currentNames.length); + } + } + } + + if (filter != 0) { + final int newLength = names.length - filter; + final String[] newNames = ArrayUtil.newStringArray(newLength); + final int[] newIds = ArrayUtil.newIntArray(newLength); + for (int i = 0, k = 0; i < names.length; i++) { + if (childrenIds[i] >= 0) { + newNames[k] = names[i]; + newIds[k] = childrenIds[i]; + //noinspection AssignmentToForLoopParameter + ++k; + } + } + names = newNames; + childrenIds = newIds; + } + + FSRecords.updateList(id, childrenIds); + int flags = FSRecords.getFlags(id); + FSRecords.setFlags(id, flags | CHILDREN_CACHED_FLAG, true); + + return Pair.create(names, childrenIds); + } + + @Override + @NotNull + public Pair listAll(@NotNull VirtualFile parent) { + final int parentId = getFileId(parent); + + Pair pair = FSRecords.listAll(parentId); + if (!areChildrenLoaded(parentId)) { + return persistAllChildren(parent, parentId, pair); + } + + return pair; + } + + private static boolean areChildrenLoaded(final int parentId) { + final int mask = CHILDREN_CACHED_FLAG; + return (FSRecords.getFlags(parentId) & mask) != 0; + } + + @Override + @Nullable + public DataInputStream readAttribute(@NotNull final VirtualFile file, @NotNull final FileAttribute att) { + return FSRecords.readAttribute(getFileId(file), att.getId()); + } + + @Override + @NotNull + public DataOutputStream writeAttribute(@NotNull final VirtualFile file, @NotNull final FileAttribute att) { + return FSRecords.writeAttribute(getFileId(file), att.getId(), att.isFixedSize()); + } + + @Nullable + private static DataInputStream readContent(@NotNull VirtualFile file) { + return FSRecords.readContent(getFileId(file)); + } + + @Nullable + private static DataInputStream readContentById(int contentId) { + return FSRecords.readContentById(contentId); + } + + @NotNull + private static DataOutputStream writeContent(@NotNull VirtualFile file, boolean readOnly) { + return FSRecords.writeContent(getFileId(file), readOnly); + } + + private static void writeContent(@NotNull VirtualFile file, ByteSequence content, boolean readOnly) throws IOException { + FSRecords.writeContent(getFileId(file), content, readOnly); + } + + @Override + public int storeUnlinkedContent(@NotNull byte[] bytes) { + return FSRecords.storeUnlinkedContent(bytes); + } + + @Override + public int getModificationCount(@NotNull final VirtualFile file) { + final int id = getFileId(file); + return FSRecords.getModCount(id); + } + + @Override + public int getCheapFileSystemModificationCount() { + return FSRecords.getLocalModCount(); + } + + @Override + public int getFilesystemModificationCount() { + return FSRecords.getModCount(); + } + + private static boolean copyRecordFromDelegateFS(final int id, + final int parentId, + @NotNull VirtualFile file, + @NotNull NewVirtualFileSystem fs, + @NotNull FileAttributes attributes) { + String name = file.getName(); + if (!name.isEmpty()) { + if (namesEqual(fs, name, FSRecords.getName(id))) return false; // TODO: Handle root attributes change. + } + else { + if (areChildrenLoaded(id)) return false; // TODO: hack + } + + FSRecords.setParent(id, parentId); + FSRecords.setName(id, name); + + FSRecords.setTimestamp(id, attributes.lastModified); + FSRecords.setLength(id, attributes.isDirectory() ? -1L : attributes.length); + + FSRecords.setFlags(id, (attributes.isDirectory() ? IS_DIRECTORY_FLAG : 0) | + (attributes.isWritable() ? 0 : IS_READ_ONLY) | + (attributes.isSymLink() ? IS_SYMLINK : 0) | + (attributes.isSpecial() ? IS_SPECIAL : 0), true); + + return true; + } + + @Override + public boolean isDirectory(@NotNull final VirtualFile file) { + final int id = getFileId(file); + return isDirectory(id); + } + + @Override + public boolean isDirectory(final int id) { + assert id > 0; + return (FSRecords.getFlags(id) & IS_DIRECTORY_FLAG) != 0; + } + + private static int getParent(final int id) { + assert id > 0; + return FSRecords.getParent(id); + } + + private static boolean namesEqual(@NotNull VirtualFileSystem fs, @NotNull String n1, String n2) { + return ((NewVirtualFileSystem)fs).isCaseSensitive() ? n1.equals(n2) : n1.equalsIgnoreCase(n2); + } + + @Override + public boolean exists(@NotNull final VirtualFile fileOrDirectory) { + return ((VirtualFileWithId)fileOrDirectory).getId() > 0; + } + + @Override + public long getTimeStamp(@NotNull final VirtualFile file) { + final int id = getFileId(file); + return FSRecords.getTimestamp(id); + } + + @Override + public void setTimeStamp(@NotNull final VirtualFile file, final long modStamp) throws IOException { + final int id = getFileId(file); + FSRecords.setTimestamp(id, modStamp); + getDelegate(file).setTimeStamp(file, modStamp); + } + + private static int getFileId(@NotNull VirtualFile file) { + final int id = ((VirtualFileWithId)file).getId(); + if (id <= 0) { + throw new InvalidVirtualFileAccessException(file); + } + return id; + } + + @Override + public boolean isSymLink(@NotNull VirtualFile file) { + return (FSRecords.getFlags(getFileId(file)) & IS_SYMLINK) != 0; + } + + @Override + public String resolveSymLink(@NotNull VirtualFile file) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isSpecialFile(@NotNull VirtualFile file) { + return (FSRecords.getFlags(getFileId(file)) & IS_SPECIAL) != 0; + } + + @Override + public boolean isWritable(@NotNull final VirtualFile file) { + return (FSRecords.getFlags(getFileId(file)) & IS_READ_ONLY) == 0; + } + + @Override + public void setWritable(@NotNull final VirtualFile file, final boolean writableFlag) throws IOException { + getDelegate(file).setWritable(file, writableFlag); + processEvent(new VFilePropertyChangeEvent(this, file, VirtualFile.PROP_WRITABLE, isWritable(file), writableFlag, false)); + } + + @Override + public int getId(@NotNull final VirtualFile parent, @NotNull final String childName, @NotNull final NewVirtualFileSystem fs) { + final int parentId = getFileId(parent); + + final int[] children = FSRecords.list(parentId); + for (final int childId : children) { + if (namesEqual(fs, childName, FSRecords.getName(childId))) return childId; + } + + final VirtualFile fake = new FakeVirtualFile(parent, childName); + final FileAttributes attributes = fs.getAttributes(fake); + if (attributes != null) { + final int child = createAndCopyRecord(fs, fake, parentId, attributes); + FSRecords.updateList(parentId, ArrayUtil.append(children, child)); + return child; + } + + return 0; + } + + @Override + public long getLength(@NotNull final VirtualFile file) { + final VirtualFile canonicalFile = file.getCanonicalFile(); + return canonicalFile == null ? 0 : getLengthNoFollow(canonicalFile); + } + + @Override + public long getLengthNoFollow(@NotNull final VirtualFile file) { + final int id = getFileId(file); + + long len = FSRecords.getLength(id); + if (len == -1) { + len = (int)getDelegate(file).getLength(file); + FSRecords.setLength(id, len); + } + + return len; + } + + @Override + public VirtualFile copyFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final VirtualFile newParent, @NotNull final String copyName) + throws IOException { + getDelegate(file).copyFile(requestor, file, newParent, copyName); + processEvent(new VFileCopyEvent(requestor, file, newParent, copyName)); + + final VirtualFile child = newParent.findChild(copyName); + if (child == null) { + throw new IOException("Cannot create child"); + } + return child; + } + + @Override + public VirtualFile createChildDirectory(final Object requestor, @NotNull final VirtualFile parent, @NotNull final String dir) throws IOException { + getDelegate(parent).createChildDirectory(requestor, parent, dir); + processEvent(new VFileCreateEvent(requestor, parent, dir, true, false)); + + final VirtualFile child = parent.findChild(dir); + if (child == null) { + throw new IOException("Cannot create child directory '" + dir + "' at " + parent.getPath()); + } + return child; + } + + @Override + public VirtualFile createChildFile(final Object requestor, @NotNull final VirtualFile parent, @NotNull final String file) throws IOException { + getDelegate(parent).createChildFile(requestor, parent, file); + processEvent(new VFileCreateEvent(requestor, parent, file, false, false)); + + final VirtualFile child = parent.findChild(file); + if (child == null) { + throw new IOException("Cannot create child file '" + file + "' at " + parent.getPath()); + } + return child; + } + + @Override + public void deleteFile(final Object requestor, @NotNull final VirtualFile file) throws IOException { + final NewVirtualFileSystem delegate = getDelegate(file); + delegate.deleteFile(requestor, file); + + if (!delegate.exists(file)) { + processEvent(new VFileDeleteEvent(requestor, file, false)); + } + } + + @Override + public void renameFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final String newName) throws IOException { + getDelegate(file).renameFile(requestor, file, newName); + processEvent(new VFilePropertyChangeEvent(requestor, file, VirtualFile.PROP_NAME, file.getName(), newName, false)); + } + + @Override + @NotNull + public byte[] contentsToByteArray(@NotNull final VirtualFile file) throws IOException { + return contentsToByteArray(file, true); + } + + @Override + @NotNull + public byte[] contentsToByteArray(@NotNull final VirtualFile file, boolean cacheContent) throws IOException { + final VirtualFile canonicalFile = getCanonicalFile(file); + + InputStream contentStream = null; + boolean reloadFromDelegate; + synchronized (INPUT_LOCK) { + reloadFromDelegate = mustReloadContent(canonicalFile) || (contentStream = readContent(canonicalFile)) == null; + } + + if (reloadFromDelegate) { + final NewVirtualFileSystem delegate = getDelegate(canonicalFile); + final byte[] content = delegate.contentsToByteArray(canonicalFile); + FSRecords.setLength(getFileId(canonicalFile), content.length); + + ApplicationEx application = (ApplicationEx)ApplicationManager.getApplication(); + // we should cache every local files content + // because the local history feature is currently depends on this cache, + // perforce offline mode as well + if ((!delegate.isReadOnly() || + // do not cache archive content unless asked + (cacheContent && !application.isInternal() && !application.isUnitTestMode())) && + content.length <= PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD) { + synchronized (INPUT_LOCK) { + writeContent(canonicalFile, new ByteSequence(content), delegate.isReadOnly()); + setFlag(canonicalFile, MUST_RELOAD_CONTENT, false); + } + } + + return content; + } + else { + try { + final int length = (int)canonicalFile.getLength(); + assert length >= 0 : canonicalFile; + return FileUtil.loadBytes(contentStream, length); + } + catch (IOException e) { + throw FSRecords.handleError(e); + } + } + } + + @Override + @NotNull + public byte[] contentsToByteArray(int contentId) throws IOException { + final DataInputStream stream = readContentById(contentId); + assert stream != null : contentId; + return FileUtil.loadBytes(stream); + } + + @Override + @NotNull + public InputStream getInputStream(@NotNull final VirtualFile file) throws IOException { + final VirtualFile canonicalFile = getCanonicalFile(file); + synchronized (INPUT_LOCK) { + InputStream contentStream; + if (mustReloadContent(canonicalFile) || (contentStream = readContent(canonicalFile)) == null) { + final NewVirtualFileSystem delegate = getDelegate(canonicalFile); + final long len = delegate.getLength(canonicalFile); + FSRecords.setLength(getFileId(canonicalFile), len); + final InputStream nativeStream = delegate.getInputStream(canonicalFile); + + if (len > PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD) return nativeStream; + return createReplicator(canonicalFile, nativeStream, len, delegate.isReadOnly()); + } + else { + return contentStream; + } + } + } + + @NotNull + private static VirtualFile getCanonicalFile(@NotNull final VirtualFile file) throws IOException { + final VirtualFile canonicalFile = file.getCanonicalFile(); + if (canonicalFile == null) { + throw new IOException("Broken link: " + file); + } + return canonicalFile; + } + + private InputStream createReplicator(@NotNull final VirtualFile file, final InputStream nativeStream, final long fileLength, final boolean readOnly) + throws IOException { + if (nativeStream instanceof BufferExposingByteArrayInputStream) { + // optimization + BufferExposingByteArrayInputStream byteStream = (BufferExposingByteArrayInputStream )nativeStream; + byte[] bytes = byteStream.getInternalBuffer(); + storeContentToStorage(fileLength, file, readOnly, bytes, bytes.length); + return nativeStream; + } + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + final BufferExposingByteArrayOutputStream cache = new BufferExposingByteArrayOutputStream((int)fileLength); + return new ReplicatorInputStream(nativeStream, cache) { + @Override + public void close() throws IOException { + super.close(); + storeContentToStorage(fileLength, file, readOnly, cache.getInternalBuffer(), cache.size()); + } + }; + } + + private void storeContentToStorage(long fileLength, + @NotNull VirtualFile file, + boolean readOnly, @NotNull byte[] bytes, int bytesLength) + throws IOException { + synchronized (INPUT_LOCK) { + if (bytesLength == fileLength) { + writeContent(file, new ByteSequence(bytes, 0, bytesLength), readOnly); + setFlag(file, MUST_RELOAD_CONTENT, false); + } + else { + setFlag(file, MUST_RELOAD_CONTENT, true); + } + } + } + + private static boolean mustReloadContent(@NotNull VirtualFile file) { + return checkFlag(file, MUST_RELOAD_CONTENT) || FSRecords.getLength(getFileId(file)) == -1L; + } + + @Override + @NotNull + public OutputStream getOutputStream(@NotNull final VirtualFile file, + final Object requestor, + final long modStamp, + final long timeStamp) throws IOException { + final VirtualFile canonicalFile = getCanonicalFile(file); + + final VFileContentChangeEvent event = new VFileContentChangeEvent(requestor, canonicalFile, canonicalFile.getModificationStamp(), modStamp, false); + + final List events = Collections.singletonList(event); + + final BulkFileListener publisher = myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES); + publisher.before(events); + + return new ByteArrayOutputStream() { + private boolean closed; // protection against user calling .close() twice + @Override + public void close() throws IOException { + if (closed) return; + super.close(); + + NewVirtualFileSystem delegate = getDelegate(canonicalFile); + OutputStream ioFileStream = delegate.getOutputStream(canonicalFile, requestor, modStamp, timeStamp); + // com.intellij.openapi.vfs.newvfs.persistent.FSRecords.ContentOutputStream already buffered, no need to wrap in BufferedStream + OutputStream persistenceStream = writeContent(canonicalFile, delegate.isReadOnly()); + + try { + persistenceStream.write(buf, 0, count); + } + finally { + try { + ioFileStream.write(buf, 0, count); + } + finally { + closed = true; + persistenceStream.close(); + ioFileStream.close(); + executeTouch(canonicalFile, false, event.getModificationStamp()); + publisher.after(events); + } + } + } + }; + } + + @Override + public int acquireContent(@NotNull VirtualFile file) { + return FSRecords.acquireFileContent(getFileId(file)); + } + + @Override + public void releaseContent(int contentId) { + FSRecords.releaseContent(contentId); + } + + @Override + public int getCurrentContentId(@NotNull VirtualFile file) { + return FSRecords.getContentId(getFileId(file)); + } + + @Override + public void moveFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final VirtualFile newParent) throws IOException { + getDelegate(file).moveFile(requestor, file, newParent); + processEvent(new VFileMoveEvent(requestor, file, newParent)); + } + + private void processEvent(@NotNull VFileEvent event) { + processEvents(Collections.singletonList(event)); + } + + private static class EventWrapper { + private final VFileDeleteEvent event; + private final int id; + + private EventWrapper(final VFileDeleteEvent event, final int id) { + this.event = event; + this.id = id; + } + } + + @NotNull private static final Comparator DEPTH_COMPARATOR = new Comparator() { + @Override + public int compare(@NotNull final EventWrapper o1, @NotNull final EventWrapper o2) { + return o1.event.getFileDepth() - o2.event.getFileDepth(); + } + }; + + @NotNull + private static List validateEvents(@NotNull List events) { + final List deletionEvents = ContainerUtil.newArrayList(); + for (int i = 0, size = events.size(); i < size; i++) { + final VFileEvent event = events.get(i); + if (event instanceof VFileDeleteEvent && event.isValid()) { + deletionEvents.add(new EventWrapper((VFileDeleteEvent)event, i)); + } + } + + ContainerUtil.quickSort(deletionEvents, DEPTH_COMPARATOR); + + final TIntHashSet invalidIDs = new TIntHashSet(deletionEvents.size()); + final List dirsToBeDeleted = new ArrayList(); + nextEvent: + for (EventWrapper wrapper : deletionEvents) { + final VirtualFile candidate = wrapper.event.getFile(); + for (VirtualFile file : dirsToBeDeleted) { + if (VfsUtilCore.isAncestor(file, candidate, false)) { + invalidIDs.add(wrapper.id); + continue nextEvent; + } + } + + if (candidate.isDirectory()) { + dirsToBeDeleted.add(candidate); + } + } + + final List filtered = ContainerUtil.newArrayListWithCapacity(events.size() - invalidIDs.size()); + for (int i = 0, size = events.size(); i < size; i++) { + final VFileEvent event = events.get(i); + if (event.isValid() && !(event instanceof VFileDeleteEvent && invalidIDs.contains(i))) { + filtered.add(event); + } + } + return filtered; + } + + @Override + public void processEvents(@NotNull List events) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + + events = validateEvents(events); + + BulkFileListener publisher = myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES); + publisher.before(events); + for (VFileEvent event : events) { + applyEvent(event); + } + publisher.after(events); + } + + @NotNull private static final Object LOCK = new Object(); + + @Override + @Nullable + public VirtualFileSystemEntry findRoot(@NotNull String basePath, @NotNull NewVirtualFileSystem fs) { // TODO: read/write locks instead of synchronized + synchronized (LOCK) { + String rootUrl = fs.getProtocol() + "://" + basePath; + VirtualFileSystemEntry root = myRoots.get(rootUrl); + if (root == null && basePath.isEmpty()) { + root = myFakeRoot; + } + if (root == null) { + try { + final int rootId = FSRecords.findRootRecord(rootUrl); + if (basePath.isEmpty()) { + // fake root for windows + root = new VirtualDirectoryImpl("", null, fs, rootId) { + @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod") + @Override + @NotNull + public VirtualFile[] getChildren() { + return getRoots(getFileSystem()); + } + + @Override + public VirtualFileSystemEntry findChild(@NotNull String name) { + if (name.isEmpty()) return null; + return findRoot(name, getFileSystem()); + } + }; + } + else { + if (fs instanceof JarFileSystem) { + // optimization: for jar roots do not store base path in the myName field, use local FS file's getPath() + String parentPath = basePath.substring(0, basePath.indexOf(JarFileSystem.JAR_SEPARATOR)); + final VirtualFile parentLocalFile = LocalFileSystem.getInstance().findFileByPath(parentPath); + if (parentLocalFile == null) return null; + root = new JarRoot(fs, rootId, parentLocalFile); + } + else { + root = new VirtualDirectoryImpl(basePath, null, fs, rootId); + } + } + + final FileAttributes attributes = fs.getAttributes(root); + if (attributes == null) { + return null; + } + + final boolean newRoot = copyRecordFromDelegateFS(rootId, 0, root, fs, attributes); + if (!newRoot) { + if (attributes.lastModified != FSRecords.getTimestamp(rootId)) { + root.markDirtyRecursively(); + } + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + + if (basePath.isEmpty()) { + myFakeRoot = root; + } + else { + myRoots.put(rootUrl, root); + myRootsById.put(root.getId(), root); + } + } + + return root; + } + } + + @Override + public void refresh(final boolean asynchronous) { + final NewVirtualFile[] roots; + synchronized (LOCK) { + Collection values = myRoots.values(); + roots = values.toArray(new NewVirtualFile[values.size()]); + } + + RefreshQueue.getInstance().refresh(asynchronous, true, null, roots); + } + + @Override + public void refresh(boolean asynchronous, Runnable postAction, @NotNull ModalityState modalityState) { + final NewVirtualFile[] roots; + synchronized (LOCK) { + Collection values = myRoots.values(); + roots = values.toArray(new NewVirtualFile[values.size()]); + } + + RefreshQueue.getInstance().refresh(asynchronous, true, postAction, modalityState, roots); + } + + @Override + @NotNull + public VirtualFile[] getLocalRoots() { + List roots; + synchronized (LOCK) { + roots = new ArrayList(myRoots.values()); + + final Iterator it = roots.iterator(); + while (it.hasNext()) { + NewVirtualFile file = it.next(); + if (!file.isInLocalFileSystem()) { + it.remove(); + } + } + } + + return VfsUtilCore.toVirtualFileArray(roots); + } + + //guarded by dirCacheReadLock/dirCacheWriteLock + @NotNull private final StripedLockIntObjectConcurrentHashMap myIdToDirCache = new StripedLockIntObjectConcurrentHashMap(); + + @Override + public void clearIdCache() { + myIdToDirCache.clear(); + } + + @Override + @Nullable + public NewVirtualFile findFileById(final int id) { + return _findFileById(id, false); + } + + @Override + public NewVirtualFile findFileByIdIfCached(final int id) { + return _findFileById(id, true); + } + + @Nullable + private NewVirtualFile _findFileById(int id, final boolean cachedOnly) { + final NewVirtualFile cached = myIdToDirCache.get(id); + if (cached != null) { + return cached; + } + + NewVirtualFile result = doFindFile(id, cachedOnly); + + if (result != null && result.isDirectory()) { + NewVirtualFile old = myIdToDirCache.putIfAbsent(id, result); + if (old != null) result = old; + } + return result; + } + + @Nullable + private NewVirtualFile doFindFile(final int id, boolean cachedOnly) { + final int parentId = getParent(id); + if (parentId == 0) { + synchronized (LOCK) { + return myRootsById.get(id); + } + } + else { + NewVirtualFile parentFile = _findFileById(parentId, cachedOnly); + if (parentFile == null) { + return null; + } + return cachedOnly ? parentFile.findChildByIdIfCached(id) : parentFile.findChildById(id); + } + } + + @Override + @NotNull + public VirtualFile[] getRoots() { + synchronized (LOCK) { + Collection roots = myRoots.values(); + return VfsUtilCore.toVirtualFileArray(roots); + } + } + + @Override + @NotNull + public VirtualFile[] getRoots(@NotNull final NewVirtualFileSystem fs) { + List roots = new ArrayList(); + synchronized (LOCK) { + for (NewVirtualFile root : myRoots.values()) { + if (root.getFileSystem() == fs) { + roots.add(root); + } + } + } + + return VfsUtilCore.toVirtualFileArray(roots); + } + + private void applyEvent(@NotNull VFileEvent event) { + try { + if (event instanceof VFileCreateEvent) { + final VFileCreateEvent createEvent = (VFileCreateEvent)event; + executeCreateChild(createEvent.getParent(), createEvent.getChildName()); + } + else if (event instanceof VFileDeleteEvent) { + final VFileDeleteEvent deleteEvent = (VFileDeleteEvent)event; + executeDelete(deleteEvent.getFile()); + } + else if (event instanceof VFileContentChangeEvent) { + final VFileContentChangeEvent contentUpdateEvent = (VFileContentChangeEvent)event; + executeTouch(contentUpdateEvent.getFile(), contentUpdateEvent.isFromRefresh(), contentUpdateEvent.getModificationStamp()); + } + else if (event instanceof VFileCopyEvent) { + final VFileCopyEvent copyEvent = (VFileCopyEvent)event; + executeCopy(copyEvent.getFile(), copyEvent.getNewParent(), copyEvent.getNewChildName()); + } + else if (event instanceof VFileMoveEvent) { + final VFileMoveEvent moveEvent = (VFileMoveEvent)event; + executeMove(moveEvent.getFile(), moveEvent.getNewParent()); + } + else if (event instanceof VFilePropertyChangeEvent) { + final VFilePropertyChangeEvent propertyChangeEvent = (VFilePropertyChangeEvent)event; + if (VirtualFile.PROP_NAME.equals(propertyChangeEvent.getPropertyName())) { + executeRename(propertyChangeEvent.getFile(), (String)propertyChangeEvent.getNewValue()); + } + else if (VirtualFile.PROP_WRITABLE.equals(propertyChangeEvent.getPropertyName())) { + executeSetWritable(propertyChangeEvent.getFile(), ((Boolean)propertyChangeEvent.getNewValue()).booleanValue()); + } + } + } + catch (Exception e) { + // Exception applying single event should not prevent other events from applying. + LOG.error(e); + } + } + + @NotNull + @NonNls + public String toString() { + return "PersistentFS"; + } + + private static void executeCreateChild(@NotNull VirtualFile parent, @NotNull String name) { + final NewVirtualFileSystem delegate = getDelegate(parent); + final VirtualFile fake = new FakeVirtualFile(parent, name); + final FileAttributes attributes = delegate.getAttributes(fake); + if (attributes != null) { + final int parentId = getFileId(parent); + final int childId = createAndCopyRecord(delegate, fake, parentId, attributes); + appendIdToParentList(parentId, childId); + assert parent instanceof VirtualDirectoryImpl : parent; + final VirtualDirectoryImpl dir = (VirtualDirectoryImpl)parent; + dir.addChild(dir.createChild(name, childId)); + } + } + + private static int createAndCopyRecord(@NotNull NewVirtualFileSystem delegateSystem, + @NotNull VirtualFile delegateFile, + int parentId, + @NotNull FileAttributes attributes) { + final int childId = FSRecords.createRecord(); + copyRecordFromDelegateFS(childId, parentId, delegateFile, delegateSystem, attributes); + return childId; + } + + private static void appendIdToParentList(final int parentId, final int childId) { + int[] childrenList = FSRecords.list(parentId); + childrenList = ArrayUtil.append(childrenList, childId); + FSRecords.updateList(parentId, childrenList); + } + + private void executeDelete(@NotNull VirtualFile file) { + if (!file.exists()) { + LOG.error("Deleting a file, which does not exist: " + file.getPath()); + } + else { + clearIdCache(); + + final int id = getFileId(file); + + final VirtualFile parent = file.getParent(); + final int parentId = parent != null ? getFileId(parent) : 0; + + FSRecords.deleteRecordRecursively(id); + + if (parentId != 0) { + removeIdFromParentList(parentId, id, parent, file); + VirtualDirectoryImpl directory = (VirtualDirectoryImpl)file.getParent(); + assert directory != null; + + directory.removeChild(file); + } + else { + synchronized (LOCK) { + myRoots.remove(file.getUrl()); + myRootsById.remove(id); + try { + FSRecords.deleteRootRecord(id); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + invalidateSubtree(file); + } + } + + private static void invalidateSubtree(@NotNull VirtualFile file) { + final VirtualFileSystemEntry impl = (VirtualFileSystemEntry)file; + impl.invalidate(); + for (VirtualFile child : impl.getCachedChildren()) { + invalidateSubtree(child); + } + } + + private static void removeIdFromParentList(final int parentId, final int id, @NotNull VirtualFile parent, VirtualFile file) { + int[] childList = FSRecords.list(parentId); + + int index = ArrayUtil.indexOf(childList, id); + if (index == -1) { + throw new RuntimeException("Cannot find child (" + id + ")" + file + + "\n\tin (" + parentId + ")" + parent + + "\n\tactual children:" + Arrays.toString(childList)); + } + childList = ArrayUtil.remove(childList, index); + FSRecords.updateList(parentId, childList); + } + + private static void executeRename(@NotNull VirtualFile file, @NotNull final String newName) { + ((VirtualFileSystemEntry)file).setNewName(newName); + final int id = getFileId(file); + FSRecords.setName(id, newName); + } + + private static void executeSetWritable(@NotNull VirtualFile file, final boolean writableFlag) { + setFlag(file, IS_READ_ONLY, !writableFlag); + } + + private static void setFlag(@NotNull VirtualFile file, int mask, boolean value) { + setFlag(getFileId(file), mask, value); + } + + private static void setFlag(final int id, final int mask, final boolean value) { + int oldFlags = FSRecords.getFlags(id); + int flags = value ? oldFlags | mask : oldFlags & ~mask; + + if (oldFlags != flags) { + FSRecords.setFlags(id, flags, true); + } + } + + private static boolean checkFlag(@NotNull VirtualFile file, int mask) { + return (FSRecords.getFlags(getFileId(file)) & mask) != 0; + } + + private static void executeTouch(@NotNull VirtualFile file, boolean reloadContentFromDelegate, long newModificationStamp) { + if (reloadContentFromDelegate) { + setFlag(file, MUST_RELOAD_CONTENT, true); + } + + final NewVirtualFileSystem delegate = getDelegate(file); + final FileAttributes attributes = delegate.getAttributes(file); + FSRecords.setLength(getFileId(file), attributes != null ? attributes.length : DEFAULT_LENGTH); + FSRecords.setTimestamp(getFileId(file), attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP); + + ((VirtualFileSystemEntry)file).setModificationStamp(newModificationStamp); + } + + @SuppressWarnings({"UnusedDeclaration"}) + private static void executeCopy(VirtualFile from, @NotNull VirtualFile newParent, @NotNull String copyName) { + executeCreateChild(newParent, copyName); + } + + private static void executeMove(@NotNull VirtualFile file, @NotNull VirtualFile newParent) { + final int fileId = getFileId(file); + final int newParentId = getFileId(newParent); + final int oldParentId = getFileId(file.getParent()); + + removeIdFromParentList(oldParentId, fileId, file.getParent(), file); + appendIdToParentList(newParentId, fileId); + + ((VirtualFileSystemEntry)file).setParent(newParent); + FSRecords.setParent(fileId, newParentId); + } + + public String getName(final int id) { + assert id > 0; + return FSRecords.getName(id); + } + + @TestOnly + public void cleanPersistedContents() { + try { + final int[] roots = FSRecords.listRoots(); + for (int root : roots) { + cleanPersistedContentsRecursively(root); + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + @TestOnly + private void cleanPersistedContentsRecursively(int id) { + if (isDirectory(id)) { + for (int child : FSRecords.list(id)) { + cleanPersistedContentsRecursively(child); + } + } + else { + setFlag(id, MUST_RELOAD_CONTENT, true); + } + } + + private static class JarRoot extends VirtualDirectoryImpl { + private final VirtualFile myParentLocalFile; + + public JarRoot(@NotNull NewVirtualFileSystem fs, int rootId, @NotNull VirtualFile parentLocalFile) { + super("", null, fs, rootId); + myParentLocalFile = parentLocalFile; + } + + @NotNull + @Override + public String getName() { + return myParentLocalFile.getName(); + } + + @Override + protected Object rawName() { + return myParentLocalFile.getPath() + JarFileSystem.JAR_SEPARATOR; + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java index cbf390134cdc..1d2454c4238f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java @@ -20,7 +20,6 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem; import com.intellij.openapi.vfs.newvfs.events.*; @@ -64,7 +63,7 @@ public class RefreshWorker { fs = PersistentFS.replaceWithNativeFS(fs); } - final PersistentFS persistence = (PersistentFS)ManagingFS.getInstance(); + final PersistentFS persistence = PersistentFS.getInstance(); while (!myRefreshQueue.isEmpty()) { final VirtualFileSystemEntry file = (VirtualFileSystemEntry)myRefreshQueue.pullFirst(); @@ -100,8 +99,13 @@ public class RefreshWorker { } for (String name : newNames) { - boolean isDirectory = fs.isDirectory(new FakeVirtualFile(file, name)); - scheduleCreation(file, name, isDirectory); + final FileAttributes childAttributes = fs.getAttributes(new FakeVirtualFile(file, name)); + if (childAttributes != null) { + scheduleCreation(file, name, childAttributes.isDirectory()); + } + else { + LOG.warn("fs=" + fs + " dir=" + file + " name=" + name); + } } for (VirtualFile child : file.getChildren()) { @@ -111,7 +115,8 @@ public class RefreshWorker { checkAndScheduleChildRefresh(file, child, childAttributes); } else { - LOG.error(child + " on " + fs); + LOG.warn("fs=" + fs + " dir=" + file + " name=" + child.getName()); + scheduleDeletion(child); } } } diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 6340ee08e1d9..a8236a81ab31 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -106,6 +106,7 @@ + diff --git a/platform/platform-resources/src/componentSets/Platform.xml b/platform/platform-resources/src/componentSets/Platform.xml index 127f417d03ca..1a80211f0e4f 100644 --- a/platform/platform-resources/src/componentSets/Platform.xml +++ b/platform/platform-resources/src/componentSets/Platform.xml @@ -27,7 +27,7 @@ com.intellij.openapi.vfs.newvfs.ManagingFS - com.intellij.openapi.vfs.newvfs.persistent.PersistentFS + com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java index 2b9d76f60b9c..ef1d34e6fc4c 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java @@ -28,6 +28,7 @@ import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent; import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl; import com.intellij.testFramework.PlatformLangTestCase; import com.intellij.testFramework.PlatformTestUtil; @@ -209,7 +210,7 @@ public class LocalFileSystemTest extends PlatformLangTestCase { assertEquals(5, virtualFile.getLength()); FileUtil.writeToFile(file, "new content"); - PersistentFS.cleanPersistedContents(); + ((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents(); s = VfsUtilCore.loadText(virtualFile); assertEquals("new content", s); assertEquals(11, virtualFile.getLength()); @@ -318,4 +319,24 @@ public class LocalFileSystemTest extends PlatformLangTestCase { assertFalse(virtualFile.exists()); assertFalse(virtualFile.isValid()); } + + public void testBadFileName() throws Exception { + if (!SystemInfo.isUnix) { + System.err.println(getName() + " skipped: " + SystemInfo.OS_NAME); + return; + } + + final File dir = FileUtil.createTempDirectory("test.", ".dir"); + final File file = FileUtil.createTempFile(dir, "test\\", "\\txt", true); + + final VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir); + assertNotNull(vDir); + assertEquals(0, vDir.getChildren().length); + + ((VirtualFileSystemEntry)vDir).markDirtyRecursively(); + vDir.refresh(false, true); + + final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + assertNull(vFile); + } } diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 923e91eaed8d..d4a52247d35e 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -76,6 +76,7 @@ import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.openapi.vfs.encoding.EncodingManagerImpl; import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl; import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; @@ -185,7 +186,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da } private static void cleanPersistedVFSContent() { - PersistentFS.cleanPersistedContents(); + ((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents(); } public static boolean isLight(Project project) { diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index ef3688abf620..94db43b18031 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -58,6 +58,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl; import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; @@ -157,7 +158,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } private static void cleanPersistedVFSContent() { - PersistentFS.cleanPersistedContents(); + ((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents(); } @Override diff --git a/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java b/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java index 302940364262..a866b0606623 100644 --- a/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java +++ b/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java @@ -33,11 +33,11 @@ import java.util.concurrent.CopyOnWriteArrayList; public class ContainerUtilRt { private static final int ARRAY_COPY_THRESHOLD = 20; - public static HashMap newHashMap() { + public static HashMap newHashMap() { return new HashMap(); } - public static HashMap newHashMap(Map map) { + public static HashMap newHashMap(Map map) { return new HashMap(map); } @@ -57,7 +57,7 @@ public class ContainerUtilRt { return new ArrayList(); } - public static ArrayList newArrayList(E ... array) { + public static ArrayList newArrayList(E... array) { ArrayList list = new ArrayList(computeArrayListCapacity(array.length)); Collections.addAll(list, array); return list; @@ -65,9 +65,8 @@ public class ContainerUtilRt { public static ArrayList newArrayList(Iterable iterable) { ArrayList list = newArrayList(); - Iterator elements = iterable.iterator(); - while (elements.hasNext()) { - list.add(elements.next()); + for (E anIterable : iterable) { + list.add(anIterable); } return list; } @@ -76,7 +75,7 @@ public class ContainerUtilRt { return new HashSet(); } - public static HashSet newHashSet(T ... elements) { + public static HashSet newHashSet(T... elements) { HashSet set = newHashSet(); Collections.addAll(set, elements); return set; @@ -88,7 +87,7 @@ public class ContainerUtilRt { public static HashSet newHashSet(Iterator iterator) { HashSet set = newHashSet(); - while(iterator.hasNext()) set.add(iterator.next()); + while (iterator.hasNext()) set.add(iterator.next()); return set; } diff --git a/platform/util/src/com/intellij/util/containers/HashMap.java b/platform/util-rt/src/com/intellij/util/containers/HashMap.java similarity index 96% rename from platform/util/src/com/intellij/util/containers/HashMap.java rename to platform/util-rt/src/com/intellij/util/containers/HashMap.java index b5ef3b8beb62..235d46edbbc8 100644 --- a/platform/util/src/com/intellij/util/containers/HashMap.java +++ b/platform/util-rt/src/com/intellij/util/containers/HashMap.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. @@ -19,6 +19,8 @@ import java.util.Map; @SuppressWarnings("ClassNameSameAsAncestorName") public class HashMap extends java.util.HashMap { + public HashMap() { } + public HashMap(int i, float v) { super(i, v); } @@ -27,8 +29,6 @@ public class HashMap extends java.util.HashMap { super(i); } - public HashMap() { } - public HashMap(Map map) { super(map); } diff --git a/platform/util/src/com/intellij/util/containers/HashSet.java b/platform/util-rt/src/com/intellij/util/containers/HashSet.java similarity index 86% rename from platform/util/src/com/intellij/util/containers/HashSet.java rename to platform/util-rt/src/com/intellij/util/containers/HashSet.java index 8d9b5eeb56d3..798de0f867e2 100644 --- a/platform/util/src/com/intellij/util/containers/HashSet.java +++ b/platform/util-rt/src/com/intellij/util/containers/HashSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -17,7 +17,8 @@ package com.intellij.util.containers; import java.util.Collection; -public class HashSet extends java.util.HashSet{ +@SuppressWarnings("ClassNameSameAsAncestorName") +public class HashSet extends java.util.HashSet { public HashSet() { } public HashSet(Collection collection) { diff --git a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java index c76e468fb2f5..01d32bb66913 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java @@ -67,7 +67,7 @@ public class FileSystemUtil { final boolean forceUseNio2 = SystemProperties.getBooleanProperty(FORCE_USE_NIO2_KEY, false); if (!forceUseNio2) { - if (SystemInfo.isWindows) { + if (SystemInfo.isWindows && IdeaWin32.isAvailable()) { try { return check(new IdeaWin32MediatorImpl()); } @@ -133,7 +133,7 @@ public class FileSystemUtil { @SuppressWarnings("UnusedDeclaration") @Nullable public static FileAttributes getAttributes(@NotNull final File file) { - return getAttributes(file.getAbsolutePath()); + return getAttributes(file.getPath()); } public static boolean isSymLink(@NotNull final String path) { diff --git a/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java b/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java index a55e18ddc39a..5365811596ef 100644 --- a/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java +++ b/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java @@ -71,7 +71,7 @@ public class IdeaWin32 { LOG.info("Native filesystem for Windows is operational"); } catch (Throwable t) { - LOG.warn("Failed to initialize native filesystem for Windows", t); + LOG.error("Failed to initialize native filesystem for Windows", t); } } ourInstance = instance; diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 2d614720e9fb..b1d0708a9b9c 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -37,6 +37,70 @@ import java.util.concurrent.CopyOnWriteArrayList; public class ContainerUtil extends ContainerUtilRt { private static final int INSERTION_SORT_THRESHOLD = 10; + public static HashMap newHashMap() { + return ContainerUtilRt.newHashMap(); + } + + public static HashMap newHashMap(Map map) { + return ContainerUtilRt.newHashMap(map); + } + + public static TreeMap newTreeMap() { + return ContainerUtilRt.newTreeMap(); + } + + public static LinkedHashMap newLinkedHashMap() { + return ContainerUtilRt.newLinkedHashMap(); + } + + public static LinkedList newLinkedList() { + return ContainerUtilRt.newLinkedList(); + } + + public static ArrayList newArrayList() { + return ContainerUtilRt.newArrayList(); + } + + public static ArrayList newArrayList(E... array) { + return ContainerUtilRt.newArrayList(array); + } + + public static ArrayList newArrayList(Iterable iterable) { + return ContainerUtilRt.newArrayList(iterable); + } + + public static HashSet newHashSet() { + return ContainerUtilRt.newHashSet(); + } + + public static HashSet newHashSet(T... elements) { + return ContainerUtilRt.newHashSet(elements); + } + + public static HashSet newHashSet(Iterable iterable) { + return ContainerUtilRt.newHashSet(iterable); + } + + public static HashSet newHashSet(Iterator iterator) { + return ContainerUtilRt.newHashSet(iterator); + } + + public static TreeSet newTreeSet() { + return ContainerUtilRt.newTreeSet(); + } + + public static TreeSet newTreeSet(Comparator comparator) { + return ContainerUtilRt.newTreeSet(comparator); + } + + public static ArrayList newArrayListWithExpectedSize(int size) { + return ContainerUtilRt.newArrayListWithExpectedSize(size); + } + + public static ArrayList newArrayListWithCapacity(int size) { + return ContainerUtilRt.newArrayListWithCapacity(size); + } + public static ConcurrentMap newConcurrentMap() { return new ConcurrentHashMap(); } diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java index c5da7754aad2..f2e683bba4da 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java @@ -108,6 +108,12 @@ public class FileAttributesReadingTest { assertFileAttributes(new File(file.getPath().replace(File.separator, File.separator + "." + File.separator))); assertFileAttributes(new File(myTempDirectory, File.separator + ".." + File.separator + myTempDirectory.getName() + File.separator + file.getName())); + + if (SystemInfo.isUnix) { + final File backSlashFile = FileUtil.createTempFile(myTempDirectory, "test\\", "\\txt", true); + FileUtil.writeToFile(backSlashFile, myTestData); + assertFileAttributes(backSlashFile); + } } @Test diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java index ed1ee2ed824b..a23a4953a162 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java @@ -28,6 +28,7 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.PlatformUtils; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -61,7 +62,7 @@ public final class VcsConfiguration implements PersistentStateComponent private Project myProject; public boolean OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT = true; - public boolean CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT = true; + public boolean CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT = !PlatformUtils.isPyCharm() && !PlatformUtils.isRubyMine(); public boolean CHECK_NEW_TODO = true; public TodoPanelSettings myTodoPanelSettings = new TodoPanelSettings(); public boolean PERFORM_UPDATE_IN_BACKGROUND = true; diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 5c766cba8318..5ceb7e183173 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -152,7 +152,7 @@ default.tostring.call.problem.descriptor=Call to default 'toString()' on # octal.and.decimal.integers.in.same.array.display.name=Octal and decimal integers in same array octal.and.decimal.integers.in.same.array.problem.descriptor=Octal and decimal integers in the same array initializer #loc result.of.object.allocation.ignored.display.name=Result of object allocation ignored -result.of.object.allocation.ignored.problem.descriptor=Result of new #ref() is ignored. #loc +result.of.object.allocation.ignored.problem.descriptor=Result of new #ref() is ignored #loc use.0index.in.jdbc.resultset.display.name=Use of index 0 in JDBC ResultSet use.0index.in.jdbc.resultset.problem.descriptor=Use of index '0' in JDBC ResultSet #loc use.0index.in.jdbc.prepared.statement.problem.descriptor=Use of index '0' in JDBC PreparedStatement #loc @@ -951,8 +951,8 @@ throw.caught.locally.problem.descriptor=#ref caught by containing ' throw.caught.locally.ignore.option=Ignore rethrown exceptions return.from.finally.block.problem.descriptor=#ref inside 'finally' block #loc continue.or.break.from.finally.block.problem.descriptor=#ref inside 'finally' block #loc -bad.exception.declared.problem.descriptor=Prohibited exception #ref declared. #loc -bad.exception.caught.problem.descriptor=Prohibited exception #ref caught. #loc +bad.exception.declared.problem.descriptor=Prohibited exception #ref declared #loc +bad.exception.caught.problem.descriptor=Prohibited exception #ref caught #loc checked.exception.class.problem.descriptor=Checked exception class #ref #loc unchecked.exception.class.problem.descriptor=Unchecked exception class #ref #loc thread.death.rethrown.problem.descriptor=#ref not rethrown #loc @@ -1458,6 +1458,8 @@ interface.never.implemented.option=Ignore interfaces which only declare constant size.replaceable.by.isempty.display.name='size() == 0' replaceable with 'isEmpty()' size.replaceable.by.isempty.quickfix=Replace with 'isEmpty()' size.replaceable.by.isempty.negation.ignore.option=Ignore expressions which would be replaced with '!isEmpty()' +ignored.classes.table=Ignored classes +choose.class.type.to.ignore=Choose class type to ignore loop.condition.not.updated.inside.loop.display.name=Loop variable not updated inside loop loop.condition.not.updated.inside.loop.problem.descriptor='#ref' is not updated inside loop #loc utility.class.without.private.constructor.option=Ignore classes with only a main method diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/EmptyClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/EmptyClassInspection.java index 7b543f7fb266..469a46e63351 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/EmptyClassInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/EmptyClassInspection.java @@ -150,12 +150,8 @@ public class EmptyClassInspection extends BaseInspection { if (initializers.length > 0) { return; } - if (ignoreClassWithParameterization) { - final PsiReferenceList extendsList = aClass.getExtendsList(); - final PsiReferenceList implementsList = aClass.getImplementsList(); - if (isSuperParameterization(extendsList) || isSuperParameterization(implementsList)) { - return; - } + if (ignoreClassWithParameterization && isSuperParametrization(aClass)) { + return; } if (AnnotationUtil.isAnnotated(aClass, ignorableAnnotations)) { return; @@ -166,7 +162,7 @@ public class EmptyClassInspection extends BaseInspection { registerClassError(aClass, aClass); } - private boolean isSuperParameterization(PsiReferenceList extendsList) { + private boolean hasTypeArguments(PsiReferenceList extendsList) { if (extendsList == null) { return false; } @@ -183,5 +179,26 @@ public class EmptyClassInspection extends BaseInspection { } return false; } + + private boolean isSuperParametrization(PsiClass aClass) { + if (!(aClass instanceof PsiAnonymousClass)) { + final PsiReferenceList extendsList = aClass.getExtendsList(); + final PsiReferenceList implementsList = aClass.getImplementsList(); + return hasTypeArguments(extendsList) || hasTypeArguments(implementsList); + } + final PsiAnonymousClass anonymousClass = (PsiAnonymousClass)aClass; + final PsiJavaCodeReferenceElement reference = anonymousClass.getBaseClassReference(); + final PsiReferenceParameterList parameterList = reference.getParameterList(); + if (parameterList == null) { + return false; + } + final PsiTypeElement[] elements = parameterList.getTypeParameterElements(); + for (PsiTypeElement element : elements) { + if (element != null) { + return true; + } + } + return false; + } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java index 092a2d1eec21..35f57a45f222 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2011 Bas Leijdekkers + * Copyright 2006-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. @@ -16,11 +16,15 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.codeInspection.ui.ListTable; +import com.intellij.codeInspection.ui.ListWrappingTableModel; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.OrderedSet; +import com.intellij.util.ui.CheckBox; import com.siyeh.HardcodedMethodConstants; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -28,36 +32,47 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.ComparisonUtils; import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.ui.UiUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; public class SizeReplaceableByIsEmptyInspection extends BaseInspection { @SuppressWarnings({"PublicField"}) public boolean ignoreNegations = false; + @SuppressWarnings("PublicField") + public OrderedSet ignoredTypes = new OrderedSet(); + @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "size.replaceable.by.isempty.display.name"); + return InspectionGadgetsBundle.message("size.replaceable.by.isempty.display.name"); } @Override @NotNull protected String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "expression.can.be.replaced.problem.descriptor", infos[0]); + return InspectionGadgetsBundle.message("expression.can.be.replaced.problem.descriptor", infos[0]); } @Override @Nullable public JComponent createOptionsPanel() { - return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message( + final JComponent panel = new JPanel(new BorderLayout()); + final ListTable table = + new ListTable(new ListWrappingTableModel(ignoredTypes, InspectionGadgetsBundle.message("ignored.classes.table"))); + JPanel tablePanel = + UiUtils.createAddRemoveTreeClassChooserPanel(table, InspectionGadgetsBundle.message("choose.class.type.to.ignore")); + final CheckBox checkBox = new CheckBox(InspectionGadgetsBundle.message( "size.replaceable.by.isempty.negation.ignore.option"), this, "ignoreNegations"); + panel.add(tablePanel, BorderLayout.CENTER); + panel.add(checkBox, BorderLayout.SOUTH); + return panel; } @Override @@ -71,8 +86,7 @@ public class SizeReplaceableByIsEmptyInspection extends BaseInspection { @NotNull public String getName() { - return InspectionGadgetsBundle.message( - "size.replaceable.by.isempty.quickfix"); + return InspectionGadgetsBundle.message("size.replaceable.by.isempty.quickfix"); } @Override @@ -195,6 +209,11 @@ public class SizeReplaceableByIsEmptyInspection extends BaseInspection { if (aClass == null) { return null; } + for (String ignoredType : ignoredTypes) { + if (InheritanceUtil.isInheritor(aClass, ignoredType)) { + return null; + } + } final PsiMethod[] methods = aClass.findMethodsByName("isEmpty", true); for (PsiMethod method : methods) { final PsiParameterList parameterList = method.getParameterList(); diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SizeReplaceableByIsEmpty.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SizeReplaceableByIsEmpty.html index 6788578061bd..4f86bb745afc 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/SizeReplaceableByIsEmpty.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SizeReplaceableByIsEmpty.html @@ -4,6 +4,10 @@ This inspection reports any .size() or .length() comparisons with a 0 literal which can be replaced with a call to .isEmpty().

+Use the table below to add classes for which any .size() or .length() comparisons should not be replaced. +

+Use the checkbox below to ignore any expressions which would be replaced with '!isEmpty()'. +

Powered by InspectionGadgets \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/emptyclass/EmptyClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/emptyclass/EmptyClass.java index 8c52556a7922..bd48fce4ff15 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/emptyclass/EmptyClass.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/emptyclass/EmptyClass.java @@ -1,9 +1,9 @@ package com.siyeh.igtest.classlayout.emptyclass; public class EmptyClass { - { - System.out.println(""); + final java.util.ArrayList stringList = new java.util.ArrayList() {}; + System.out.println(""); } } class MyList extends java.util.ArrayList {} diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CompoundProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CompoundProperty.java index 6b52c3ee2ffd..6ba7956181e5 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CompoundProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CompoundProperty.java @@ -93,16 +93,6 @@ public class CompoundProperty extends Property implements IPro return value.toString(); } - @Override - public boolean isDefaultValue(@NotNull RadViewComponent component) throws Exception { - for (Property childProperty : myChildren) { - if (!childProperty.isDefaultValue(component)) { - return false; - } - } - return true; - } - @Override public void setDefaultValue(@NotNull RadViewComponent component) throws Exception { for (Property childProperty : myChildren) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/artifact/AndroidArtifactPropertiesEditor.form b/plugins/android/src/org/jetbrains/android/compiler/artifact/AndroidArtifactPropertiesEditor.form index 7d095d126721..2553e5d7e187 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/artifact/AndroidArtifactPropertiesEditor.form +++ b/plugins/android/src/org/jetbrains/android/compiler/artifact/AndroidArtifactPropertiesEditor.form @@ -16,7 +16,7 @@ - + diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java index 19cb6ecf3e13..9a2af1a933b8 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurable.java @@ -18,6 +18,7 @@ package org.jetbrains.android.sdk; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.projectRoots.*; +import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -77,7 +78,10 @@ public class AndroidSdkConfigurable implements AdditionalDataConfigurable { public boolean isModified() { final AndroidSdkAdditionalData data = (AndroidSdkAdditionalData)mySdk.getSdkAdditionalData(); Sdk javaSdk = data != null ? data.getJavaSdk() : null; - return javaSdk != myForm.getSelectedSdk(); + final String javaSdkHomePath = javaSdk != null ? javaSdk.getHomePath() : null; + final Sdk selectedSdk = myForm.getSelectedSdk(); + final String selectedSdkHomePath = selectedSdk != null ? selectedSdk.getHomePath() : null; + return !FileUtil.pathsEqual(javaSdkHomePath, selectedSdkHomePath); } @Override diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java index d9d8d43f00d7..843436443639 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkConfigurableForm.java @@ -49,6 +49,8 @@ class AndroidSdkConfigurableForm { private final DefaultComboBoxModel myBuildTargetsModel = new DefaultComboBoxModel(); private String mySdkLocation; + private boolean myFreeze = false; + public AndroidSdkConfigurableForm(@NotNull SdkModel sdkModel, @NotNull final SdkModificator sdkModificator) { mySdkModel = sdkModel; myInternalJdkComboBox.setModel(myJdksModel); @@ -76,6 +78,9 @@ class AndroidSdkConfigurableForm { myBuildTargetComboBox.addItemListener(new ItemListener() { public void itemStateChanged(final ItemEvent e) { + if (myFreeze) { + return; + } final IAndroidTarget target = (IAndroidTarget)e.getItem(); List roots = AndroidSdkUtils.getLibraryRootsForTarget(target, mySdkLocation); @@ -138,18 +143,10 @@ class AndroidSdkConfigurableForm { mySdkLocation = androidSdk != null ? androidSdk.getHomePath() : null; AndroidSdkData androidSdkData = mySdkLocation != null ? AndroidSdkData.parse(mySdkLocation, new EmptySdkLog()) : null; - updateBuildTargets(androidSdkData); - if (buildTarget != null) { - for (int i = 0; i < myBuildTargetsModel.getSize(); i++) { - IAndroidTarget target = (IAndroidTarget)myBuildTargetsModel.getElementAt(i); - if (buildTarget.hashString().equals(target.hashString())) { - myBuildTargetComboBox.setSelectedIndex(i); - return; - } - } - } - myBuildTargetComboBox.setSelectedItem(null); + myFreeze = true; + updateBuildTargets(androidSdkData, buildTarget); + myFreeze = false; } private void updateJdks() { @@ -161,7 +158,7 @@ class AndroidSdkConfigurableForm { } } - private void updateBuildTargets(AndroidSdkData androidSdkData) { + private void updateBuildTargets(AndroidSdkData androidSdkData, IAndroidTarget buildTarget) { myBuildTargetsModel.removeAllElements(); if (androidSdkData != null) { @@ -169,6 +166,17 @@ class AndroidSdkConfigurableForm { myBuildTargetsModel.addElement(target); } } + + if (buildTarget != null) { + for (int i = 0; i < myBuildTargetsModel.getSize(); i++) { + IAndroidTarget target = (IAndroidTarget)myBuildTargetsModel.getElementAt(i); + if (buildTarget.hashString().equals(target.hashString())) { + myBuildTargetComboBox.setSelectedIndex(i); + return; + } + } + } + myBuildTargetComboBox.setSelectedItem(null); } public void addJavaSdk(Sdk sdk) { diff --git a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java index 3f6226b52c0a..bbfaa51f3aa3 100644 --- a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java +++ b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java @@ -27,6 +27,7 @@ import org.jetbrains.jps.devkit.model.JpsIdeaSdkType; import org.jetbrains.jps.devkit.model.JpsPluginModuleProperties; import org.jetbrains.jps.incremental.artifacts.JpsSyntheticArtifactProvider; import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.JpsElementFactory; import org.jetbrains.jps.model.JpsModel; import org.jetbrains.jps.model.JpsSimpleElement; import org.jetbrains.jps.model.artifact.DirectoryArtifactType; @@ -61,8 +62,10 @@ public class JpsPluginSyntheticArtifactProvider extends JpsSyntheticArtifactProv for (JpsModule module : model.getProject().getModules()) { JpsElement propertiesElement = module.getProperties(); if (propertiesElement instanceof JpsSimpleElement) { - JpsPluginModuleProperties properties = ((JpsSimpleElement)propertiesElement).getProperties(); - artifacts.add(createArtifact(module, properties)); + Object properties = ((JpsSimpleElement)propertiesElement).getProperties(); + if (properties instanceof JpsPluginModuleProperties) { + artifacts.add(createArtifact(module, (JpsPluginModuleProperties)properties)); + } } } return artifacts; @@ -120,7 +123,7 @@ public class JpsPluginSyntheticArtifactProvider extends JpsSyntheticArtifactProv } String name = module.getName() + ":plugin"; - JpsArtifact artifact = JpsArtifactService.getInstance().createArtifact(name, root, DirectoryArtifactType.INSTANCE); + JpsArtifact artifact = JpsArtifactService.getInstance().createArtifact(name, root, DirectoryArtifactType.INSTANCE, JpsElementFactory.getInstance().createDummyElement()); JpsTypedLibrary sdk = module.getSdk(JpsIdeaSdkType.INSTANCE); if (sdk != null) { diff --git a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/JpsPluginModuleProperties.java b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/JpsPluginModuleProperties.java index edf0243eeb3d..b70cdf12246c 100644 --- a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/JpsPluginModuleProperties.java +++ b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/JpsPluginModuleProperties.java @@ -15,21 +15,27 @@ */ package org.jetbrains.jps.devkit.model; +import org.jetbrains.annotations.Nullable; + /** * @author nik */ public class JpsPluginModuleProperties { private final String myPluginXmlUrl; + private final String myManifestFileUrl; - public JpsPluginModuleProperties(String pluginXmlUrl) { + public JpsPluginModuleProperties(@Nullable String pluginXmlUrl, @Nullable String manifestFileUrl) { myPluginXmlUrl = pluginXmlUrl; + myManifestFileUrl = manifestFileUrl; } - public JpsPluginModuleProperties(JpsPluginModuleProperties properties) { - myPluginXmlUrl = properties.getPluginXmlUrl(); - } - + @Nullable public String getPluginXmlUrl() { return myPluginXmlUrl; } + + @Nullable + public String getManifestFileUrl() { + return myManifestFileUrl; + } } diff --git a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/impl/JpsDevKitModelSerializerExtension.java b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/impl/JpsDevKitModelSerializerExtension.java index 7eb16728c6a0..a1fe8e9b217a 100644 --- a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/impl/JpsDevKitModelSerializerExtension.java +++ b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/model/impl/JpsDevKitModelSerializerExtension.java @@ -76,15 +76,35 @@ public class JpsDevKitModelSerializerExtension extends JpsModelSerializerExtensi } private static class JpsPluginModulePropertiesSerializer extends JpsModulePropertiesSerializer> { + private static final String URL_ATTRIBUTE = "url"; + private static final String MANIFEST_ATTRIBUTE = "manifest"; + private static final String COMPONENT_NAME = "DevKit.ModuleBuildProperties"; + private JpsPluginModulePropertiesSerializer() { super(JpsPluginModuleType.INSTANCE, "PLUGIN_MODULE"); } @Override public JpsSimpleElement loadProperties(@Nullable Element moduleRootElement) { - Element component = JpsLoaderBase.findComponent(moduleRootElement, "DevKit.ModuleBuildProperties"); - String pluginXmlUrl = component != null ? component.getAttributeValue("url") : null; - return JpsElementFactory.getInstance().createSimpleElement(new JpsPluginModuleProperties(pluginXmlUrl)); + Element component = JpsLoaderBase.findComponent(moduleRootElement, COMPONENT_NAME); + String pluginXmlUrl = component != null ? component.getAttributeValue(URL_ATTRIBUTE) : null; + String manifestFileUrl = component != null ? component.getAttributeValue(MANIFEST_ATTRIBUTE) : null; + return JpsElementFactory.getInstance().createSimpleElement(new JpsPluginModuleProperties(pluginXmlUrl, manifestFileUrl)); + } + + @Override + public void saveProperties(@NotNull JpsSimpleElement element, @NotNull Element moduleRootElement) { + Element component = JpsLoaderBase.findComponent(moduleRootElement, COMPONENT_NAME); + if (component != null) { + String pluginXmlUrl = element.getProperties().getPluginXmlUrl(); + if (pluginXmlUrl != null) { + component.setAttribute(URL_ATTRIBUTE, pluginXmlUrl); + } + String manifestFileUrl = element.getProperties().getManifestFileUrl(); + if (manifestFileUrl != null) { + component.setAttribute(MANIFEST_ATTRIBUTE, manifestFileUrl); + } + } } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/strings/ConvertConcatenationToGstringIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/strings/ConvertConcatenationToGstringIntention.java index d102b6875abb..6fd84ee408ff 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/strings/ConvertConcatenationToGstringIntention.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/strings/ConvertConcatenationToGstringIntention.java @@ -20,6 +20,8 @@ import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pass; @@ -103,18 +105,19 @@ public class ConvertConcatenationToGstringIntention extends Intention { finally { accessToken.finish(); } + final Document document = editor.getDocument(); if (expressions.size() == 1) { - invokeImpl(expressions.get(0)); + invokeImpl(expressions.get(0), document); } else if (expressions.size() > 0) { if (ApplicationManager.getApplication().isUnitTestMode()) { - invokeImpl(expressions.get(expressions.size() - 1)); + invokeImpl(expressions.get(expressions.size() - 1), document); return; } IntroduceTargetChooser.showChooser(editor, expressions, new Pass() { public void pass(final GrExpression selectedValue) { - invokeImpl(selectedValue); + invokeImpl(selectedValue, document); } }, new Function() { @@ -127,7 +130,7 @@ public class ConvertConcatenationToGstringIntention extends Intention { } } - private static void invokeImpl(PsiElement element) { + private static void invokeImpl(final PsiElement element, Document document) { boolean isMultiline = containsMultilineStrings((GrExpression)element); StringBuilder builder = new StringBuilder(element.getTextLength()); @@ -145,16 +148,21 @@ public class ConvertConcatenationToGstringIntention extends Intention { final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(element.getProject()); final GrExpression newExpr = factory.createExpressionFromText(GrStringUtil.addQuotes(text, true)); - final AccessToken accessToken = WriteAction.start(); - try { - final GrExpression expression = ((GrExpression)element).replaceWithExpression(newExpr, true); - if (expression instanceof GrString) { - GrStringUtil.removeUnnecessaryBracesInGString((GrString)expression); + CommandProcessor.getInstance().executeCommand(element.getProject(), new Runnable() { + @Override + public void run() { + final AccessToken accessToken = WriteAction.start(); + try { + final GrExpression expression = ((GrExpression)element).replaceWithExpression(newExpr, true); + if (expression instanceof GrString) { + GrStringUtil.removeUnnecessaryBracesInGString((GrString)expression); + } + } + finally { + accessToken.finish(); + } } - } - finally { - accessToken.finish(); - } + }, null, null, document); } private static boolean containsMultilineStrings(GrExpression expr) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java index 4df7481c0b13..9d96eb56de04 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java @@ -20,8 +20,10 @@ import com.intellij.psi.PsiReference; import com.intellij.util.ThreeState; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.console.GroovyShellAction; +import org.jetbrains.plugins.groovy.extensions.GroovyScriptTypeDetector; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrForStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -45,6 +47,11 @@ public class GroovyCompletionConfidence extends CompletionConfidence { public ThreeState shouldFocusLookup(@NotNull CompletionParameters parameters) { final PsiElement position = parameters.getPosition(); + PsiFile file = position.getContainingFile(); + if (file instanceof GroovyFile && GroovyScriptTypeDetector.getScriptType((GroovyFile)file) != GroovyScriptTypeDetector.DEFAULT_TYPE) { + return ThreeState.NO; + } + if (position.getParent() instanceof GrReferenceElement && psiElement().afterLeaf(psiElement().withText("(").withParent(GrForStatement.class)).accepts(position)) { return ThreeState.NO; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java index ade42083d029..43c6e3dfb94f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java @@ -531,7 +531,6 @@ public abstract class GroovyRefactoringUtil { argText.append("["); for (PsiElement argument : arguments) { argText.append(argument.getText()).append(", "); - argument.delete(); } if (arguments.size() > 0) { argText.delete(argText.length() - 2, argText.length()); @@ -547,7 +546,7 @@ public abstract class GroovyRefactoringUtil { } return GroovyPsiElementFactory.getInstance(project).createExpressionFromText(argText.toString()); } - + public static boolean hasSideEffect(@NotNull GroovyPsiElement statement) { final Ref hasSideEffect = new Ref(false); statement.accept(new GroovyRecursiveElementVisitor() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java index fb1a2d0f04c7..45c03785f339 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java @@ -516,6 +516,9 @@ public class GrChangeSignatureUsageProcessor implements ChangeSignatureUsageProc (i != parameters.length - 1 || !parameter.isVarargType())) { final PsiType type = parameter.createType(changeInfo.getMethod().getParameterList(), argumentList.getManager()); final GrExpression arg = GroovyRefactoringUtil.generateArgFromMultiArg(substitutor, arguments, type, element.getProject()); + for (PsiElement argument : arguments) { + argument.delete(); + } anchor = argumentList.addAfter(arg, anchor); GrReferenceAdjuster.shortenReferences(anchor); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/inline/InlineMethodTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/inline/InlineMethodTest.groovy similarity index 74% rename from plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/inline/InlineMethodTest.java rename to plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/inline/InlineMethodTest.groovy index dd062fd96550..a2a29ecb32a7 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/inline/InlineMethodTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/inline/InlineMethodTest.groovy @@ -13,39 +13,33 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.refactoring.inline; - -import com.intellij.lang.ASTNode; -import com.intellij.lang.refactoring.InlineHandler; -import com.intellij.openapi.editor.Editor; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; -import com.intellij.psi.impl.source.tree.TreeElement; -import com.intellij.refactoring.inline.GenericInlineHandler; -import com.intellij.refactoring.util.CommonRefactoringUtil; -import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture; -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import junit.framework.Assert; -import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; -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.refactoring.GroovyRefactoringUtil; -import org.jetbrains.plugins.groovy.util.TestUtils; - -import java.util.List; +package org.jetbrains.plugins.groovy.refactoring.inline +import com.intellij.lang.ASTNode +import com.intellij.lang.refactoring.InlineHandler +import com.intellij.openapi.editor.Editor +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.impl.source.codeStyle.CodeEditUtil +import com.intellij.psi.impl.source.tree.TreeElement +import com.intellij.refactoring.inline.GenericInlineHandler +import com.intellij.refactoring.util.CommonRefactoringUtil +import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import junit.framework.Assert +import org.jetbrains.plugins.groovy.GroovyFileType +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable +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.refactoring.GroovyRefactoringUtil +import org.jetbrains.plugins.groovy.util.TestUtils /** * @author ilyas */ public class InlineMethodTest extends LightCodeInsightFixtureTestCase { - @Override - protected String getBasePath() { - return TestUtils.getTestDataPath() + "groovy/refactoring/inlineMethod/"; - } + final String basePath = TestUtils.testDataPath + "groovy/refactoring/inlineMethod/"; public void testAbstr1() throws Throwable { doTest(); } public void testBlock1() throws Throwable { doTest(); } @@ -105,31 +99,27 @@ public class InlineMethodTest extends LightCodeInsightFixtureTestCase { public void testVarargs() {doTest();} - public void testInlineAll() throws Throwable { + public void testInlineAll() { doTest(new GroovyInlineHandler() { @Override - public Settings prepareInlineElement(PsiElement element, Editor editor, boolean invokedOnReference) { - return new Settings() { + public InlineHandler.Settings prepareInlineElement(PsiElement element, Editor editor, boolean invokedOnReference) { + return new InlineHandler.Settings() { @Override - public boolean isOnlyOneReferenceToInline() { - return false; - } - }; + boolean isOnlyOneReferenceToInline() {false} + } } - }); + }) } - public void testInlineNamedArgs() { - doTest(); - } + public void testInlineNamedArgs() {doTest(); } + public void testInlineVarargs() {doTest()} protected void doTest() { doTest(new GroovyInlineHandler()); - } protected void doTest(InlineHandler handler) { - doInlineTest(myFixture, getTestDataPath() + getTestName(true) + ".test", handler); + doInlineTest(myFixture, testDataPath + getTestName(true) + ".test", handler); } public static void doInlineTest(final JavaCodeInsightTestFixture fixture, @@ -140,32 +130,32 @@ public class InlineMethodTest extends LightCodeInsightFixtureTestCase { fixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, fileText); - final PsiFile file = fixture.getFile(); - final Editor editor = fixture.getEditor(); - setIndentationToNode(file.getNode()); - int startOffset = editor.getSelectionModel().getSelectionStart(); - int endOffset = editor.getSelectionModel().getSelectionEnd(); - editor.getCaretModel().moveToOffset(endOffset); + final PsiFile file = fixture.file; + final Editor editor = fixture.editor; + indentationToNode = file.node; + int startOffset = editor.selectionModel.selectionStart; + int endOffset = editor.selectionModel.selectionEnd; + editor.caretModel.moveToOffset(endOffset); GroovyPsiElement selectedArea = GroovyRefactoringUtil.findElementInRange(file, startOffset, endOffset, GrReferenceExpression.class); if (selectedArea == null) { PsiElement identifier = GroovyRefactoringUtil.findElementInRange(file, startOffset, endOffset, PsiElement.class); if (identifier != null){ - Assert.assertTrue("Selected area doesn't point to method", identifier.getParent() instanceof GrVariable); - selectedArea = (GroovyPsiElement)identifier.getParent(); + Assert.assertTrue("Selected area doesn't point to method", identifier.parent instanceof GrVariable); + selectedArea = (GroovyPsiElement)identifier.parent; } } Assert.assertNotNull("Selected area reference points to nothing", selectedArea); - PsiElement element = selectedArea instanceof GrExpression ? selectedArea.getReference().resolve() : selectedArea; + PsiElement element = selectedArea instanceof GrExpression ? selectedArea.reference.resolve() : selectedArea; Assert.assertNotNull("Cannot resolve selected reference expression", element); try { GenericInlineHandler.invoke(element, editor, inlineHandler); - editor.getSelectionModel().removeSelection(); + editor.selectionModel.removeSelection(); fixture.checkResult(data.get(1), true); } catch (CommonRefactoringUtil.RefactoringErrorHintException e) { - assertEquals(data.get(1), "FAIL: " + e.getMessage()); + assertEquals(data.get(1), "FAIL: " + e.message); } } @@ -174,7 +164,7 @@ public class InlineMethodTest extends LightCodeInsightFixtureTestCase { CodeEditUtil.setOldIndentation(((TreeElement) element), 0); } for (ASTNode node : element.getChildren(null)) { - setIndentationToNode(node); + indentationToNode = node; } } diff --git a/plugins/groovy/testdata/groovy/refactoring/inlineMethod/inlineVarargs.test b/plugins/groovy/testdata/groovy/refactoring/inlineMethod/inlineVarargs.test new file mode 100644 index 000000000000..109044728d2d --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/inlineMethod/inlineVarargs.test @@ -0,0 +1,18 @@ +void foo(String... s) { + println 'hello' + bar(s) +} + +void bar(String... s) {} + +foo("foo", "bar") +----- +void foo(String... s) { + println 'hello' + bar(s) +} + +void bar(String... s) {} + +println 'hello' +bar(["foo", "bar"] as java.lang.String[]) \ No newline at end of file diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java index 169080277b91..7ccb889706b5 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java @@ -73,7 +73,7 @@ public class MavenDomUtil { String name = file.getName(); return name.equals(MavenConstants.POM_XML) || - name.endsWith("." + MavenConstants.POM_EXTENSION) || + name.endsWith(".pom") || name.equals(MavenConstants.SUPER_POM_XML); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java index b158e037a399..297cee031579 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java @@ -135,7 +135,7 @@ public class MavenFoldersImporter { } @NotNull - private List> normalize(@NotNull List> folders) { + private static List> normalize(@NotNull List> folders) { List> result = new ArrayList>(folders.size()); for (Pair eachToAdd : folders) { addSourceFolder(eachToAdd, result); @@ -143,7 +143,7 @@ public class MavenFoldersImporter { return result; } - private void addSourceFolder(Pair folder, List> result) { + private static void addSourceFolder(Pair folder, List> result) { for (Pair eachExisting : result) { if (MavenRootModelAdapter.isEqualOrAncestor(eachExisting.first.getPath(), folder.first.getPath()) || MavenRootModelAdapter.isEqualOrAncestor(folder.first.getPath(), eachExisting.first.getPath())) { @@ -178,9 +178,11 @@ public class MavenFoldersImporter { configGeneratedSourceFolder(f, isGeneratedTestSources); } else { - if (myModel.hasRegisteredSourceSubfolder(f)) continue; - if (myModel.isAlreadyExcluded(f)) continue; - myModel.addExcludedFolder(f.getPath()); + if (myImportingSettings.isExcludeTargetFolder()) { + if (myModel.hasRegisteredSourceSubfolder(f)) continue; + if (myModel.isAlreadyExcluded(f)) continue; + myModel.addExcludedFolder(f.getPath()); + } } } @@ -196,8 +198,14 @@ public class MavenFoldersImporter { myModel.addExcludedFolder(eachFolder); } - if (!myModel.hasRegisteredSourceSubfolder(targetDir)) { - myModel.addExcludedFolder(targetDir.getPath()); + if (myImportingSettings.isExcludeTargetFolder()) { + if (!myModel.hasRegisteredSourceSubfolder(targetDir)) { + myModel.addExcludedFolder(targetDir.getPath()); + } + } + else { + myModel.addExcludedFolder(myMavenProject.getOutputDirectory()); + myModel.addExcludedFolder(myMavenProject.getTestOutputDirectory()); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java index c14446f2eda7..4c17940aff71 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java @@ -259,7 +259,7 @@ public class MavenModuleImporter { List processors = myMavenProject.getDeclaredAnnotationProcessors(); - if (processors == null && options.isEmpty() && "target/generated-sources/annotations".equals(annotationProcessorDirectory)) { + if (processors == null && options.isEmpty() && "target/generated-sources/annotations".equals(annotationProcessorDirectory.replace('\\', '/'))) { if (moduleProfile != null) { compilerConfiguration.removeModuleProcessorProfile(moduleProfile); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java index ed73c334a3d5..d7ad131b1b2a 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java @@ -86,6 +86,7 @@ public class MavenProjectImporter { myModuleModel = modelsProvider.getModuleModel(); } + @Nullable public List importProject() { List postTasks = new ArrayList(); @@ -100,6 +101,8 @@ public class MavenProjectImporter { mapMavenProjectsToModulesAndNames(); + if (myProject.isDisposed()) return null; + boolean projectsHaveChanges = projectsToImportHaveChanges(); if (projectsHaveChanges) { hasChanges = true; @@ -112,6 +115,8 @@ public class MavenProjectImporter { configModuleGroups(); } + if (myProject.isDisposed()) return null; + boolean modulesDeleted = deleteObsoleteModules(); hasChanges |= modulesDeleted; if (hasChanges) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenGeneralConfigurable.form b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenGeneralConfigurable.form index 7bc25cb9ae5f..e6917d0c59e1 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenGeneralConfigurable.form +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenGeneralConfigurable.form @@ -77,6 +77,7 @@ + @@ -86,6 +87,7 @@ + @@ -97,6 +99,7 @@ + @@ -107,6 +110,7 @@ + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettings.java index dab37f367960..4a1bc4f0ed02 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettings.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettings.java @@ -40,6 +40,7 @@ public class MavenImportingSettings implements Cloneable { private boolean importAutomatically = false; private boolean createModulesForAggregators = true; private boolean createModuleGroups = false; + private boolean excludeTargetFolder = true; private boolean keepSourceFolders = true; private boolean useMavenOutput = true; private String updateFoldersOnImportPhase = UPDATE_FOLDERS_DEFAULT_PHASE; @@ -115,6 +116,14 @@ public class MavenImportingSettings implements Cloneable { this.keepSourceFolders = keepSourceFolders; } + public boolean isExcludeTargetFolder() { + return excludeTargetFolder; + } + + public void setExcludeTargetFolder(boolean excludeTargetFolder) { + this.excludeTargetFolder = excludeTargetFolder; + } + public boolean isUseMavenOutput() { return useMavenOutput; } @@ -173,6 +182,7 @@ public class MavenImportingSettings implements Cloneable { if (downloadSourcesAutomatically != that.downloadSourcesAutomatically) return false; if (lookForNested != that.lookForNested) return false; if (keepSourceFolders != that.keepSourceFolders) return false; + if (excludeTargetFolder != that.excludeTargetFolder) return false; if (useMavenOutput != that.useMavenOutput) return false; if (generatedSourcesFolder != that.generatedSourcesFolder) return false; if (!dedicatedModuleDir.equals(that.dedicatedModuleDir)) return false; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form index 48df1820fa0a..7e93b3dc0c04 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form @@ -1,9 +1,9 @@

- + - + @@ -34,15 +34,16 @@ - + + - + @@ -54,12 +55,13 @@ + - + @@ -108,7 +110,7 @@ - + @@ -116,7 +118,7 @@ - + @@ -176,13 +178,13 @@ - + - + @@ -211,7 +213,7 @@ - + @@ -226,7 +228,7 @@ - + @@ -252,6 +254,15 @@ + + + + + + + + + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java index fe2caaeba0ba..3384aa27d2f7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java @@ -51,6 +51,7 @@ public class MavenImportingSettingsForm { private JPanel myAdditionalSettingsPanel; private JPanel mySeparateModulesDirPanel; private JComboBox myGeneratedSourcesComboBox; + private JCheckBox myExcludeTargetFolderCheckBox; public MavenImportingSettingsForm(boolean isImportStep, boolean isCreatingNewProject) { mySearchRecursivelyCheckBox.setVisible(isImportStep); @@ -111,6 +112,7 @@ public class MavenImportingSettingsForm { data.setCreateModuleGroups(myCreateGroupsCheckBox.isSelected()); data.setKeepSourceFolders(myKeepSourceFoldersCheckBox.isSelected()); + data.setExcludeTargetFolder(myExcludeTargetFolderCheckBox.isSelected()); data.setUseMavenOutput(myUseMavenOutputCheckBox.isSelected()); data.setUpdateFoldersOnImportPhase((String)myUpdateFoldersOnImportPhaseComboBox.getSelectedItem()); @@ -131,6 +133,7 @@ public class MavenImportingSettingsForm { myCreateGroupsCheckBox.setSelected(data.isCreateModuleGroups()); myKeepSourceFoldersCheckBox.setSelected(data.isKeepSourceFolders()); + myExcludeTargetFolderCheckBox.setSelected(data.isExcludeTargetFolder()); myUseMavenOutputCheckBox.setSelected(data.isUseMavenOutput()); myUpdateFoldersOnImportPhaseComboBox.setSelectedItem(data.getUpdateFoldersOnImportPhase()); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenProblemFileHighlighter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenProblemFileHighlighter.java index 20b2b3293c0b..96f3bee1713c 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenProblemFileHighlighter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenProblemFileHighlighter.java @@ -15,30 +15,29 @@ */ package org.jetbrains.idea.maven.utils; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import org.jetbrains.idea.maven.dom.MavenDomUtil; +import org.jetbrains.idea.maven.model.MavenConstants; public class MavenProblemFileHighlighter implements Condition { - private final Project myProject; - - public MavenProblemFileHighlighter(Project project) { - myProject = project; - } public boolean value(final VirtualFile file) { - AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock(); - try { - PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file); - return psiFile != null && MavenDomUtil.isMavenFile(psiFile); + String fileName = file.getName(); + + // MavenDomUtil.isProjectFile(PsiFile) + if (fileName.equals(MavenConstants.POM_XML) || fileName.endsWith(".pom") || fileName.equals(MavenConstants.SUPER_POM_XML)) { + return true; } - finally { - accessToken.finish(); + + // MavenDomUtil.isProfilesFile(PsiFile) + if (fileName.equals(MavenConstants.PROFILES_XML)) { + return true; } + + if (fileName.equals(MavenConstants.SETTINGS_XML)) { + return true; + } + + return false; } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java index 925792a728d3..bbe7e5e2cec8 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java @@ -445,6 +445,8 @@ public class MavenUtil { Runnable runnable = new Runnable() { public void run() { + if (project.isDisposed()) return; + try { task.run(indicator); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachDialog.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachDialog.java index d28d69e34379..6b580f0bcb7e 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachDialog.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachDialog.java @@ -238,8 +238,9 @@ public class RepositoryAttachDialog extends DialogWrapper { final int prevSize = myCoordinates.size(); for (Pair each : artifacts) { myCoordinates.put(each.first.getGroupId() + ":" + each.first.getArtifactId() + ":" + each.first.getVersion(), each); - if (each.second != null && !myRepositories.containsKey(each.second.getUrl())) { - myRepositories.put(each.second.getUrl(), each.second); + String url = each.second != null? each.second.getUrl() : null; + if (StringUtil.isNotEmpty(url) && !myRepositories.containsKey(url)) { + myRepositories.put(url, each.second); } } String title = getTitle(); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenDontExcludeTargetTest.groovy b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenDontExcludeTargetTest.groovy new file mode 100644 index 000000000000..39a09731606a --- /dev/null +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenDontExcludeTargetTest.groovy @@ -0,0 +1,82 @@ +/* + * 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 org.jetbrains.idea.maven.importing + +import com.intellij.openapi.roots.ProjectRootManager +import org.jetbrains.idea.maven.MavenImportingTestCase +import org.jetbrains.idea.maven.project.MavenProjectsManager +/** + * @author Sergey Evdokimov + */ +class MavenDontExcludeTargetTest extends MavenImportingTestCase { + + public void testDontExcludeTargetTest() { + MavenProjectsManager.getInstance(myProject).importingSettings.excludeTargetFolder = false + + def classA = createProjectSubFile("target/classes/A.class") + def testClass = createProjectSubFile("target/test-classes/ATest.class") + + def a = createProjectSubFile("target/a.txt") + def aaa = createProjectSubFile("target/aaa/a.txt") + + importProject """ +test +project +1 +""" + + def fileIndex = ProjectRootManager.getInstance(myProject).fileIndex + + assert !fileIndex.isInContent(classA) + assert !fileIndex.isInContent(testClass) + assert fileIndex.isInContent(a) + assert fileIndex.isInContent(aaa) + } + + public void testDontExcludeTargetTest2() { + MavenProjectsManager.getInstance(myProject).importingSettings.excludeTargetFolder = false + + def realClassA = createProjectSubFile("customOutput/A.class") + def realTestClass = createProjectSubFile("customTestOutput/ATest.class") + + def classA = createProjectSubFile("target/classes/A.class") + def testClass = createProjectSubFile("target/test-classes/ATest.class") + + def a = createProjectSubFile("target/a.txt") + def aaa = createProjectSubFile("target/aaa/a.txt") + + importProject """ +test +project +1 + + +customOutput +customTestOutput + +""" + + def fileIndex = ProjectRootManager.getInstance(myProject).fileIndex + + assert fileIndex.isInContent(classA) + assert fileIndex.isInContent(testClass) + assert fileIndex.isInContent(a) + assert fileIndex.isInContent(aaa) + assert !fileIndex.isInContent(realClassA) + assert !fileIndex.isInContent(realTestClass) + } + +} diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 99005a3eb456..722dc3d42ae0 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -344,7 +344,9 @@ reindex renderer repo resetlogs +resizable resize +resizeable rethrow rethrowing rethrown diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java index 3e7fb0977ace..d0342822db07 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -113,9 +113,12 @@ public class DomElementAnnotationHolderImpl extends SmartList T addProblem(final T problemDescriptor) { diff --git a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java index 4691a0a33ca9..d4692d5acc87 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java @@ -107,7 +107,7 @@ public abstract class DomElementsInspection extends XmlSup } /** - * Not intended to be overriden or called by implementors. + * Not intended to be overridden or called by implementors. * Override {@link #checkFileElement(com.intellij.util.xml.DomFileElement, DomElementAnnotationHolder)} (which is preferred) or * {@link #checkDomElement(com.intellij.util.xml.DomElement, DomElementAnnotationHolder, DomHighlightingHelper)} instead. */ @@ -117,6 +117,7 @@ public abstract class DomElementsInspection extends XmlSup for (Class domClass: myDomClasses) { final DomFileElement fileElement = DomManager.getDomManager(file.getProject()).getFileElement((XmlFile)file, domClass); if (fileElement != null) { + //noinspection unchecked return checkDomFile((DomFileElement)fileElement, manager, isOnTheFly); } } @@ -134,15 +135,17 @@ public abstract class DomElementsInspection extends XmlSup } /** - * not intended to be overriden or called by implementors + * not intended to be overridden or called by implementors */ @Nullable protected ProblemDescriptor[] checkDomFile(@NotNull final DomFileElement domFileElement, @NotNull final InspectionManager manager, - final boolean isOnTheFly) { + @SuppressWarnings("UnusedParameters") final boolean isOnTheFly) { final DomElementAnnotationsManager annotationsManager = DomElementAnnotationsManager.getInstance(manager.getProject()); final List list = annotationsManager.checkFileElement(domFileElement, this); + if (list.isEmpty()) return ProblemDescriptor.EMPTY_ARRAY; + List problems = ContainerUtil.concat(list, new Function>() { public Collection fun(final DomElementProblemDescriptor s) { diff --git a/xml/impl/src/com/intellij/javaee/DefaultHtmlDoctypeConverter.java b/xml/impl/src/com/intellij/javaee/DefaultHtmlDoctypeConverter.java new file mode 100644 index 000000000000..7a5c0244b5c6 --- /dev/null +++ b/xml/impl/src/com/intellij/javaee/DefaultHtmlDoctypeConverter.java @@ -0,0 +1,92 @@ +package com.intellij.javaee; + +import com.intellij.conversion.*; +import com.intellij.openapi.util.io.FileUtil; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; +import java.util.Collections; + +/** + * @author Eugene.Kudelevsky + */ +public class DefaultHtmlDoctypeConverter extends ConverterProvider { + protected DefaultHtmlDoctypeConverter() { + super("default-html-language-level"); + } + + @NotNull + @Override + public String getConversionDescription() { + return "Default HTML language level setting will be updated"; + } + + @NotNull + @Override + public ProjectConverter createConverter(@NotNull ConversionContext context) { + return new MyConverter(context); + } + + private static class MyConverter extends ProjectConverter { + private final ConversionContext myContext; + + private MyConverter(@NotNull ConversionContext context) { + myContext = context; + } + + @Override + public boolean isConversionNeeded() { + return getElementToUpdate() != null; + } + + @Override + public void preProcessingFinished() throws CannotConvertException { + final Element defaultHtmlDoctype = getElementToUpdate(); + + if (defaultHtmlDoctype != null) { + defaultHtmlDoctype.setText(ExternalResourceManagerImpl.HTML5_DOCTYPE_ELEMENT); + } + } + + @Nullable + private Element getElementToUpdate() { + final ComponentManagerSettings settings = myContext.getProjectRootManagerSettings(); + if (settings == null) { + return null; + } + + final Element root = settings.getComponentElement("ProjectResources"); + if (root == null) { + return null; + } + + Element defaultHtmlDoctype = root.getChild("default-html-language-level"); + if (defaultHtmlDoctype == null) { + return null; + } + + String value = defaultHtmlDoctype.getTextTrim(); + value = value != null ? myContext.expandPath(value) : null; + if (value == null) { + return null; + } + + if (!FileUtil.toSystemIndependentName(value).endsWith("idea.jar!/resources/html5-schema/html5.rnc")) { + return null; + } + return defaultHtmlDoctype; + } + + @Override + public Collection getAdditionalAffectedFiles() { + final ComponentManagerSettings settings = myContext.getProjectRootManagerSettings(); + final File file = settings != null ? settings.getFile() : null; + return file != null + ? Collections.singletonList(file) + : Collections.emptyList(); + } + } +} diff --git a/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java b/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java index be0783628e78..32d1a1be74ec 100644 --- a/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java +++ b/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java @@ -101,10 +101,12 @@ public class ExternalResourceManagerImpl extends ExternalResourceManagerEx imple @NonNls private static final String URL_ATTR = "url"; @NonNls private static final String LOCATION_ATTR = "location"; @NonNls private static final String IGNORED_RESOURCE_ELEMENT = "ignored-resource"; - @NonNls private static final String HTML_DEFAULT_DOCTYPE_ELEMENT = "default-html-doctype"; + @NonNls private static final String HTML_DEFAULT_DOCTYPE_ELEMENT = "default-html-language-level"; private static final String DEFAULT_VERSION = null; @NonNls public static final String STANDARD_SCHEMAS = "/standardSchemas/"; + public static String HTML5_DOCTYPE_ELEMENT = "HTML5"; + public ExternalResourceManagerImpl(PathMacrosImpl pathMacros) { myPathMacros = pathMacros; } @@ -361,7 +363,14 @@ public class ExternalResourceManagerImpl extends ExternalResourceManagerEx imple Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT); if (child != null) { - myDefaultHtmlDoctype = child.getText(); + final String text = child.getText(); + + if (HTML5_DOCTYPE_ELEMENT.equals(text)) { + myDefaultHtmlDoctype = Html5SchemaProvider.HTML5_SCHEMA_LOCATION; + } + else { + myDefaultHtmlDoctype = text; + } } Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT); if (catalogElement != null) { @@ -392,7 +401,14 @@ public class ExternalResourceManagerImpl extends ExternalResourceManagerEx imple if (myDefaultHtmlDoctype != null) { final Element e = new Element(HTML_DEFAULT_DOCTYPE_ELEMENT); - e.setText(myDefaultHtmlDoctype); + + if (Html5SchemaProvider.HTML5_SCHEMA_LOCATION.equals(myDefaultHtmlDoctype)) { + // do not store the path to html5 schema in project settings + e.setText(HTML5_DOCTYPE_ELEMENT); + } + else { + e.setText(myDefaultHtmlDoctype); + } element.addContent(e); } if (myCatalogPropertiesFile != null) { diff --git a/xml/impl/src/com/intellij/xml/Html5SchemaProvider.java b/xml/impl/src/com/intellij/xml/Html5SchemaProvider.java index 729c9395a61f..218498bfc497 100644 --- a/xml/impl/src/com/intellij/xml/Html5SchemaProvider.java +++ b/xml/impl/src/com/intellij/xml/Html5SchemaProvider.java @@ -3,8 +3,9 @@ package com.intellij.xml; import com.intellij.javaee.ExternalResourceManagerImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.util.io.URLUtil; import org.jetbrains.annotations.NotNull; import java.net.URL; @@ -46,12 +47,12 @@ public abstract class Html5SchemaProvider { xhtmlSchemaLocationURL = htmlSchemaLocationURL; } - HTML5_SCHEMA_LOCATION = - VfsUtil.urlToPath(VfsUtil.fixURLforIDEA(FileUtil.unquote(htmlSchemaLocationURL.toExternalForm()))); + HTML5_SCHEMA_LOCATION = VfsUtilCore.urlToPath(VfsUtil.fixURLforIDEA( + URLUtil.unescapePercentSequences(htmlSchemaLocationURL.toExternalForm()))); LOG.info("HTML5_SCHEMA_LOCATION = " + HTML5_SCHEMA_LOCATION); - XHTML5_SCHEMA_LOCATION = - VfsUtil.urlToPath(VfsUtil.fixURLforIDEA(FileUtil.unquote(xhtmlSchemaLocationURL.toExternalForm()))); + XHTML5_SCHEMA_LOCATION = VfsUtilCore.urlToPath(VfsUtil.fixURLforIDEA( + URLUtil.unescapePercentSequences(xhtmlSchemaLocationURL.toExternalForm()))); LOG.info("XHTML5_SCHEMA_LOCATION = " + XHTML5_SCHEMA_LOCATION); }