diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index ef49e7357182..c36ccf8a38d4 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -250,7 +250,7 @@ public def layoutCommunityPlugins(String home) { } dir("plugins") { - def simplePlugins = ["commander", "copyright", "java-i18n", "hg4idea", "github", "ui-designer-core"] //, "tasks-time-tracking"] + def simplePlugins = ["commander", "copyright", "java-i18n", "hg4idea", "github"] //, "tasks-time-tracking"] simplePlugins.each { layoutPlugin it @@ -678,9 +678,19 @@ def layoutAndroid(String androidHome) { } } - layoutPlugin("android-designer") { - jar("android-designer.jar") { - module("android-designer") + dir("android-designer") { + dir("lib") { + jar("resources_en.jar") { + module("ui-designer-core") { + patternset(refid: "resources.included") + } + } + jar("android-designer.jar") { + module("ui-designer-core") { + patternset(refid: "resources.excluded") + } + module("android-designer") + } } } } diff --git a/images/src/org/intellij/images/index/ImageInfoIndex.java b/images/src/org/intellij/images/index/ImageInfoIndex.java index 28838b5e316d..f2db1b48fc33 100644 --- a/images/src/org/intellij/images/index/ImageInfoIndex.java +++ b/images/src/org/intellij/images/index/ImageInfoIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -46,14 +46,14 @@ public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension myValueExternalizer = new DataExternalizer() { @Override - public void save(final DataOutput out, final ImageInfo info) throws IOException { + public void save(@NotNull final DataOutput out, final ImageInfo info) throws IOException { DataInputOutputUtil.writeINT(out, info.width); DataInputOutputUtil.writeINT(out, info.height); DataInputOutputUtil.writeINT(out, info.bpp); } @Override - public ImageInfo read(final DataInput in) throws IOException { + public ImageInfo read(@NotNull final DataInput in) throws IOException { return new ImageInfo(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)); } }; @@ -83,16 +83,18 @@ public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension getValueExternalizer() { return myValueExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(ImageFileTypeManager.getInstance().getImageFileType()) { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return file.isInLocalFileSystem() && file.getLength() / 1024 < ourMaxImageSize ; diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.java b/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.java index bd56b6653b91..631988e17577 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; import com.intellij.util.io.PersistentHashMap; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -92,11 +93,11 @@ public abstract class StateCache { private PersistentHashMap createMap(final File file) throws IOException { return new PersistentHashMap(file, new EnumeratorStringDescriptor(), new DataExternalizer() { - public void save(final DataOutput out, final T value) throws IOException { + public void save(@NotNull final DataOutput out, final T value) throws IOException { StateCache.this.write(value, out); } - public T read(final DataInput in) throws IOException { + public T read(@NotNull final DataInput in) throws IOException { return StateCache.this.read(in); } }); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index 5b208a6d165e..2dd5838ccf7d 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -196,7 +196,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { return; } FileUtil.createIfDoesntExist(CompilerPaths.getRebuildMarkerFile(project)); - --myWatchedProjectsCount; + if (myWatchedProjectsCount > 0) --myWatchedProjectsCount; if (ourDebugMode) { System.out.println("After suspend for project:"+projectId + "," + myWatchedProjectsCount); } @@ -607,7 +607,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { private void initOutputRootsFile(File rootsFile) throws IOException { myOutputRootsStorage = new PersistentHashMap>>(rootsFile, EnumeratorIntegerDescriptor.INSTANCE, new DataExternalizer>>() { - public void save(DataOutput out, TIntObjectHashMap> value) throws IOException { + public void save(@NotNull DataOutput out, TIntObjectHashMap> value) throws IOException { for (final TIntObjectIterator> it = value.iterator(); it.hasNext();) { it.advance(); DataInputOutputUtil.writeINT(out, it.key()); @@ -617,7 +617,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } } - public TIntObjectHashMap> read(DataInput in) throws IOException { + public TIntObjectHashMap> read(@NotNull DataInput in) throws IOException { final DataInputStream _in = (DataInputStream)in; final TIntObjectHashMap> map = new TIntObjectHashMap>(); while (_in.available() > 0) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java b/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java index 5741b9cf7949..4db878623df7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -112,8 +112,8 @@ public class GenericCompilerCache { } public static class PersistentStateData { - public final SourceState mySourceState; - public final OutputState myOutputState; + @NotNull public final SourceState mySourceState; + @NotNull public final OutputState myOutputState; private PersistentStateData(@NotNull SourceState sourceState, @NotNull OutputState outputState) { mySourceState = sourceState; @@ -139,14 +139,14 @@ public class GenericCompilerCache { } @Override - public void save(DataOutput out, KeyAndTargetData value) throws IOException { + public void save(@NotNull DataOutput out, KeyAndTargetData value) throws IOException { out.writeInt(value.myTarget); myKeyDescriptor.save(out, value.myKey); } @Override - public KeyAndTargetData read(DataInput in) throws IOException { + public KeyAndTargetData read(@NotNull DataInput in) throws IOException { int target = in.readInt(); final Key item = myKeyDescriptor.read(in); return getKeyAndTargetData(item, target); @@ -163,13 +163,13 @@ public class GenericCompilerCache { } @Override - public void save(DataOutput out, PersistentStateData value) throws IOException { + public void save(@NotNull DataOutput out, PersistentStateData value) throws IOException { mySourceStateExternalizer.save(out, value.mySourceState); myOutputStateExternalizer.save(out, value.myOutputState); } @Override - public PersistentStateData read(DataInput in) throws IOException { + public PersistentStateData read(@NotNull DataInput in) throws IOException { SourceState sourceState = mySourceStateExternalizer.read(in); OutputState outputState = myOutputStateExternalizer.read(in); return new PersistentStateData(sourceState, outputState); diff --git a/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java b/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java index fb7a5c6eb280..006debb3b43a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -357,7 +357,7 @@ public class BackwardDependenciesStorage implements Flushable, Disposable { } private static class MyDataExternalizer implements DataExternalizer { - public void save(DataOutput out, DependenciesSet ds) throws IOException { + public void save(@NotNull DataOutput out, DependenciesSet ds) throws IOException { final TIntHashSet classes = new TIntHashSet(); final Map fieldsMap = new HashMap(); final Map methodsMap = new HashMap(); @@ -414,7 +414,7 @@ public class BackwardDependenciesStorage implements Flushable, Disposable { } } - public DependenciesSet read(DataInput in) throws IOException { + public DependenciesSet read(@NotNull DataInput in) throws IOException { final Set set = new THashSet(); int classesCount = in.readInt(); diff --git a/java/compiler/impl/src/com/intellij/compiler/make/Cache.java b/java/compiler/impl/src/com/intellij/compiler/make/Cache.java index 2e3d5543214b..f80cb8e5bcaa 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/Cache.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/Cache.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -25,6 +25,7 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorIntegerDescriptor; import com.intellij.util.io.PersistentHashMap; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; @@ -54,10 +55,10 @@ public class Cache { myStorePath = storePath; new File(storePath).mkdirs(); myQNameToClassInfoMap = new CachedPersistentHashMap(getOrCreateFile("classes"), EnumeratorIntegerDescriptor.INSTANCE, new DataExternalizer() { - public void save(DataOutput out, ClassInfo value) throws IOException { + public void save(@NotNull DataOutput out, ClassInfo value) throws IOException { value.save(out); } - public ClassInfo read(DataInput in) throws IOException { + public ClassInfo read(@NotNull DataInput in) throws IOException { return new ClassInfo(in); } }, cacheSize * 2) { @@ -71,11 +72,11 @@ public class Cache { myQNameToSubclassesMap = new CompilerDependencyStorage(getOrCreateFile("subclasses"), EnumeratorIntegerDescriptor.INSTANCE, cacheSize); myRemoteQNames = new PersistentHashMap(getOrCreateFile("remote"), EnumeratorIntegerDescriptor.INSTANCE, new DataExternalizer() { - public void save(DataOutput out, Boolean value) throws IOException { + public void save(@NotNull DataOutput out, Boolean value) throws IOException { out.writeBoolean(value.booleanValue()); } - public Boolean read(DataInput in) throws IOException { + public Boolean read(@NotNull DataInput in) throws IOException { return in.readBoolean(); } }, cacheSize); diff --git a/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.java b/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.java index ea93f2193297..2466881b14fd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -40,14 +40,14 @@ public class CompilerDependencyStorage implements Flushable, Disposable { public CompilerDependencyStorage(File file, KeyDescriptor keyDescriptor, final int cacheSize) throws IOException { myMap = new PersistentHashMap(file, keyDescriptor, new DataExternalizer() { - public void save(DataOutput out, int[] array) throws IOException { + public void save(@NotNull DataOutput out, int[] array) throws IOException { out.writeInt(array.length); for (int value : array) { out.writeInt(value); } } - public int[] read(DataInput in) throws IOException { + public int[] read(@NotNull DataInput in) throws IOException { final TIntHashSet set = new TIntHashSet(); DataInputStream stream = (DataInputStream)in; while(stream.available() > 0) { diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java index b3d66ce575fb..495b5a08758f 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,6 +16,7 @@ package com.intellij.openapi.compiler.generic; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -33,11 +34,11 @@ public class DummyPersistentState { private static class DummyPersistentStateExternalizer implements DataExternalizer { @Override - public void save(DataOutput out, DummyPersistentState value) throws IOException { + public void save(@NotNull DataOutput out, DummyPersistentState value) throws IOException { } @Override - public DummyPersistentState read(DataInput in) throws IOException { + public DummyPersistentState read(@NotNull DataInput in) throws IOException { return INSTANCE; } } diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java index e9ea9700af42..17739b154aa6 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,6 +16,7 @@ package com.intellij.openapi.compiler.generic; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -38,12 +39,12 @@ public class VirtualFilePersistentState { private static class VirtualFileStateExternalizer implements DataExternalizer { @Override - public void save(DataOutput out, VirtualFilePersistentState value) throws IOException { + public void save(@NotNull DataOutput out, VirtualFilePersistentState value) throws IOException { out.writeLong(value.getSourceTimestamp()); } @Override - public VirtualFilePersistentState read(DataInput in) throws IOException { + public VirtualFilePersistentState read(@NotNull DataInput in) throws IOException { return new VirtualFilePersistentState(in.readLong()); } diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java index a22e80dd77de..cf74b55f6691 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -67,7 +67,7 @@ public class VirtualFileSetState { private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, VirtualFileSetState value) throws IOException { + public void save(@NotNull DataOutput out, VirtualFileSetState value) throws IOException { final Map dependencies = value.myTimestamps; out.writeInt(dependencies.size()); for (Map.Entry entry : dependencies.entrySet()) { @@ -77,7 +77,7 @@ public class VirtualFileSetState { } @Override - public VirtualFileSetState read(DataInput in) throws IOException { + public VirtualFileSetState read(@NotNull DataInput in) throws IOException { final VirtualFileSetState state = new VirtualFileSetState(); int size = in.readInt(); while (size-- > 0) { diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java index 9f4a815304de..1b9aee4254a7 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -63,7 +63,7 @@ public class VirtualFileWithDependenciesState { private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, VirtualFileWithDependenciesState value) throws IOException { + public void save(@NotNull DataOutput out, VirtualFileWithDependenciesState value) throws IOException { out.writeLong(value.mySourceTimestamp); final Map dependencies = value.myDependencies; out.writeInt(dependencies.size()); @@ -74,7 +74,7 @@ public class VirtualFileWithDependenciesState { } @Override - public VirtualFileWithDependenciesState read(DataInput in) throws IOException { + public VirtualFileWithDependenciesState read(@NotNull DataInput in) throws IOException { final VirtualFileWithDependenciesState state = new VirtualFileWithDependenciesState(in.readLong()); int size = in.readInt(); while (size-- > 0) { diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java index 030e9484ba26..c0a547e817d1 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.util.SmartList; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.IOUtil; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -31,7 +32,7 @@ public class ArtifactPackagingItemExternalizer implements DataExternalizer pair : value.myDestinations) { IOUtil.writeUTFFast(myBuffer, out, pair.getFirst()); @@ -40,7 +41,7 @@ public class ArtifactPackagingItemExternalizer implements DataExternalizer> destinations = new SmartList>(); while (size-- > 0) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java index f52100aec91b..4eda8984e285 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java @@ -69,10 +69,7 @@ public final class TextWithImportsImpl implements TextWithImports{ } private static Trinity parseExternalForm(String s) { - // when serialized into a tag special symbols are now kept as is - // so our separator \r may be converted to \n or \r\n - s = StringUtil.convertLineSeparators(s); - String[] split = s.split("\n"); + String[] split = s.split(String.valueOf(DebuggerEditorImpl.SEPARATOR)); return Trinity.create(split[0], split.length > 1 ? split[1] : "", split.length > 2 ? FileTypeManager.getInstance().getStdFileType(split[2]) : null); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java index aac9ffd510c3..c682325b2366 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java @@ -587,6 +587,9 @@ public class BreakpointManager { breakpoint.updateUI(); RequestManagerImpl.createRequests(breakpoint); myDispatcher.getMulticaster().breakpointsChanged(); + if (breakpoint instanceof MethodBreakpoint || breakpoint instanceof WildcardMethodBreakpoint) { + XDebugSessionImpl.NOTIFICATION_GROUP.createNotification("Method breakpoints may dramatically slow down debugging", MessageType.WARNING).notify(myProject); + } } private synchronized void onBreakpointAdded(XBreakpoint xBreakpoint) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java index 14d7bf4bcd22..0fa93846da88 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java @@ -108,21 +108,13 @@ public abstract class JavaLineBreakpointTypeBase

= 0) { @@ -130,18 +122,28 @@ public abstract class JavaLineBreakpointTypeBase

= document.getLineEndOffset(line)) { - PsiCodeBlock body = ((PsiMethod)child).getBody(); - if(body != null) { - PsiStatement[] statements = body.getStatements(); - if (statements.length > 0 && document.getLineNumber(statements[0].getTextOffset()) == line) { - result.set(JavaLineBreakpointType.class); + if(parent instanceof PsiMethod) { + if (parent.getTextRange().getEndOffset() >= document.getLineEndOffset(line)) { + PsiCodeBlock body = ((PsiMethod)parent).getBody(); + if (body != null) { + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0 && document.getLineNumber(statements[0].getTextOffset()) == line) { + result.set(JavaLineBreakpointType.class); + } } } + if (result.isNull()) { + result.set(JavaMethodBreakpointType.class); + } + } + else if (parent instanceof PsiField) { + if (result.isNull()) { + result.set(JavaFieldBreakpointType.class); + } } else { result.set(JavaLineBreakpointType.class); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 4e9d79fecf57..352e74557eed 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -1324,8 +1324,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); if (!myHolder.hasErrorResults()) { - for (PsiType type : list.getTypeArguments()) { - myHolder.add(HighlightUtil.checkDiamondFeature(type, list, myLanguageLevel,myFile)); + for (PsiTypeElement typeElement : list.getTypeParameterElements()) { + myHolder.add(HighlightUtil.checkDiamondFeature(typeElement.getType(), list, myLanguageLevel,myFile)); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java index 76580adaa5f4..b4a8d5b99d17 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,14 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Created by IntelliJ IDEA. - * User: cdr - * Date: Nov 13, 2002 - * Time: 3:26:50 PM - * To change this template use Options | File Templates. - */ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.FileModificationService; @@ -32,6 +24,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -39,11 +32,18 @@ import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.util.ObjectUtils.assertNotNull; + +/** + * @author cdr + * @since Nov 13, 2002 + */ public class ChangeTypeArgumentsFix implements IntentionAction, HighPriorityAction { + private static final Logger LOG = Logger.getInstance("#" + ChangeTypeArgumentsFix.class.getName()); + private final PsiMethod myTargetMethod; private final PsiClass myPsiClass; private final PsiExpression[] myExpressions; - private static final Logger LOG = Logger.getInstance("#" + ChangeTypeArgumentsFix.class.getName()); private final PsiNewExpression myNewExpression; ChangeTypeArgumentsFix(@NotNull PsiMethod targetMethod, @@ -116,11 +116,12 @@ public class ChangeTypeArgumentsFix implements IntentionAction, HighPriorityActi LOG.assertTrue(reference != null, myNewExpression); final PsiReferenceParameterList parameterList = reference.getParameterList(); LOG.assertTrue(parameterList != null, myNewExpression); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); PsiTypeElement[] elements = parameterList.getTypeParameterElements(); for (int i = elements.length - 1; i >= 0; i--) { - PsiTypeElement typeElement = elements[i]; - final PsiType typeArg = psiSubstitutor.substitute(typeParameters[i]); - typeElement.replace(JavaPsiFacade.getElementFactory(project).createTypeElement(typeArg)); + PsiType typeArg = assertNotNull(psiSubstitutor.substitute(typeParameters[i])); + PsiElement replaced = elements[i].replace(factory.createTypeElement(typeArg)); + JavaCodeStyleManager.getInstance(file.getProject()).shortenClassReferences(replaced); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java index 987f02dc9c39..84f704f64dcd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java @@ -64,15 +64,25 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement { } @Nullable - public static PsiModifierListOwner getContainer(final PsiElement element) { - PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false); - if (listOwner == null) { - final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false); - if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) { - listOwner = (PsiModifierListOwner)psiIdentifier.getParent(); + public static PsiModifierListOwner getContainer(final PsiFile file, int offset) { + PsiReference reference = file.findReferenceAt(offset); + if (reference != null) { + PsiElement target = reference.resolve(); + if (target instanceof PsiMember) { + return (PsiMember)target; } } - return listOwner; + + PsiElement element = file.findElementAt(offset); + + PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false); + if (listOwner != null) return listOwner; + + final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false); + if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) { + return (PsiModifierListOwner)psiIdentifier.getParent(); + } + return null; } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java index 6684613f0ab0..272ce37708ad 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java @@ -41,7 +41,7 @@ public class AddNullableNotNullAnnotationFix extends AddAnnotationPsiFix { if (!super.isAvailable(project, file, startElement, endElement)) { return false; } - PsiModifierListOwner owner = getContainer(startElement); + PsiModifierListOwner owner = getContainer(file, startElement.getTextRange().getStartOffset()); if (owner == null || AnnotationUtil.isAnnotated(owner, getAnnotationsToRemove()[0], false, false)) { return false; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java index 8101d16f5a1e..03d23ddd62d0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java @@ -106,9 +106,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } }); - if (effectivelyFinal[0] && !isTrivial(body, statement.getIterationParameter(), iteratedValueType)) { - holder.registerProblem(iteratedValue, "Can be replaced with foreach call", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithForeachCallFix()); + if (effectivelyFinal[0]) { + if (isCollectCall(body)) { + holder.registerProblem(iteratedValue, "Can be replaced with collect call", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithCollectCallFix()); + } else if (!isTrivial(body, statement.getIterationParameter(), iteratedValueType)) { + holder.registerProblem(iteratedValue, "Can be replaced with foreach call", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithForeachCallFix()); + } } } } @@ -121,10 +126,42 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo }; } + private static boolean isCollectCall(PsiStatement body) { + final PsiMethodCallExpression methodCallExpression = extractAddCall(body); + if (methodCallExpression != null) { + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + PsiClass qualifierClass = null; + if (qualifierExpression instanceof PsiReferenceExpression) { + qualifierClass = PsiUtil.resolveClassInType(qualifierExpression.getType()); + } else if (qualifierExpression == null) { + final PsiClass enclosingClass = PsiTreeUtil.getParentOfType(body, PsiClass.class); + if (PsiUtil.getEnclosingStaticElement(body, enclosingClass) == null) { + qualifierClass = enclosingClass; + } + } + + if (qualifierClass != null && + InheritanceUtil.isInheritor(qualifierClass, false, CommonClassNames.JAVA_UTIL_COLLECTION)) { + + final PsiElement resolve = methodExpression.resolve(); + if (resolve instanceof PsiMethod && + "add".equals(((PsiMethod)resolve).getName()) && + ((PsiMethod)resolve).getParameterList().getParametersCount() == 1) { + final PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions(); + if (args.length == 1) { + return true; + } + } + } + } + return false; + } + private static boolean isTrivial(PsiStatement body, PsiParameter parameter, PsiType iteratedValueType) { final PsiIfStatement ifStatement = extractIfStatement(body); //stream - if (ifStatement != null && ifStatement.getElseBranch() == null && ifStatement.getThenBranch() != null && + if (ifStatement != null && InheritanceUtil.isInheritor(iteratedValueType, CommonClassNames.JAVA_UTIL_COLLECTION)) { return false; } @@ -157,11 +194,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo String foreEachText = body.getText(); String iterated = iteratedValue.getText(); - if (ifStmt != null && ifStmt.getElseBranch() == null) { + if (ifStmt != null) { final PsiExpression condition = ifStmt.getCondition(); if (condition != null) { final PsiStatement thenBranch = ifStmt.getThenBranch(); - if (thenBranch != null && InheritanceUtil.isInheritor(iteratedValue.getType(), CommonClassNames.JAVA_UTIL_COLLECTION)) { + LOG.assertTrue(thenBranch != null); + if (InheritanceUtil.isInheritor(iteratedValue.getType(), CommonClassNames.JAVA_UTIL_COLLECTION)) { body = thenBranch; foreEachText = thenBranch.getText(); iterated += ".stream().filter(" + parameter.getName() + " -> " + condition.getText() +")"; @@ -191,6 +229,76 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } + private static class ReplaceWithCollectCallFix implements LocalQuickFix { + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @NotNull + @Override + public String getFamilyName() { + return "Replace with collect"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiForeachStatement foreachStatement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiForeachStatement.class); + if (foreachStatement != null) { + PsiStatement body = foreachStatement.getBody(); + final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); + if (body != null && iteratedValue != null) { + final PsiParameter parameter = foreachStatement.getIterationParameter(); + + final PsiIfStatement ifStatement = extractIfStatement(body); + final PsiMethodCallExpression methodCallExpression = extractAddCall(body); + String iteration = iteratedValue.getText() + ".stream()"; + if (ifStatement != null) { + final PsiExpression condition = ifStatement.getCondition(); + if (condition != null) { + iteration += ".filter(" + parameter.getName() + " -> " + condition.getText() +")"; + } + } + iteration +=".map(" + parameter.getName() + " -> " + methodCallExpression.getArgumentList().getExpressions()[0].getText() + ").collect(java.util.stream.Collectors."; + + String variableName = null; + PsiExpression initializer = null; + final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); + if (qualifierExpression instanceof PsiReferenceExpression) { + final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); + if (resolve instanceof PsiVariable) { + if (resolve instanceof PsiLocalVariable && foreachStatement.equals(PsiTreeUtil.skipSiblingsForward(resolve.getParent(), PsiWhiteSpace.class))) { + initializer = ((PsiVariable)resolve).getInitializer(); + } + variableName = ((PsiVariable)resolve).getName() + "."; + } + } else if (qualifierExpression == null) { + variableName = ""; + } + + if (initializer != null) { + final PsiType initializerType = initializer.getType(); + final PsiClassType rawType = initializerType instanceof PsiClassType ? ((PsiClassType)initializerType).rawType() : null; + if (rawType != null && rawType.equalsToText(CommonClassNames.JAVA_UTIL_ARRAY_LIST)) { + iteration += "toList()"; + } else if (rawType != null && rawType.equalsToText(CommonClassNames.JAVA_UTIL_HASH_SET)) { + iteration += "toSet()"; + } else { + iteration += "toCollection(() -> " + initializer.getText() +")"; + } + iteration += ")"; + initializer.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(iteration, foreachStatement)); + foreachStatement.delete(); + } else if (variableName != null){ + iteration += "toList())"; + foreachStatement.replace(JavaPsiFacade.getElementFactory(project).createStatementFromText(variableName + "addAll(" + iteration +");", foreachStatement)); + } + } + } + } + } + public static PsiIfStatement extractIfStatement(PsiStatement body) { PsiIfStatement ifStmt = null; if (body instanceof PsiIfStatement) { @@ -201,6 +309,34 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo ifStmt = (PsiIfStatement)statements[0]; } } - return ifStmt; + if (ifStmt != null && ifStmt.getElseBranch() == null && ifStmt.getThenBranch() != null) { + return ifStmt; + } + return null; + } + + private static PsiMethodCallExpression extractAddCall(PsiStatement body) { + final PsiIfStatement ifStatement = extractIfStatement(body); + if (ifStatement != null) { + return extractAddCall(ifStatement.getThenBranch()); + } + PsiExpressionStatement stmt = null; + if (body instanceof PsiBlockStatement) { + final PsiStatement[] statements = ((PsiBlockStatement)body).getCodeBlock().getStatements(); + if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement) { + stmt = (PsiExpressionStatement)statements[0]; + } + } + else if (body instanceof PsiExpressionStatement) { + stmt = (PsiExpressionStatement)body; + } + + if (stmt != null) { + final PsiExpression expression = stmt.getExpression(); + if (expression instanceof PsiMethodCallExpression) { + return (PsiMethodCallExpression)expression; + } + } + return null; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java index ccb1c3c369e4..5d51949c1d6b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -52,7 +52,9 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { PsiDocumentManager.getInstance(project).commitAllDocuments(); PsiElement element = findElement(file, offset); - PsiTryStatement tryStatement = (PsiTryStatement) element.getParent(); + if (element == null) return; + + PsiTryStatement tryStatement = (PsiTryStatement)element.getParent(); List unhandledExceptions = new ArrayList(ExceptionUtil.collectUnhandledExceptions(element, null)); ExceptionUtil.sortExceptionsByHierarchy(unhandledExceptions); @@ -86,7 +88,9 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { } } - private static PsiCodeBlock addCatchStatement(PsiTryStatement tryStatement, PsiClassType exceptionType, PsiFile file) throws IncorrectOperationException { + private static PsiCodeBlock addCatchStatement(PsiTryStatement tryStatement, + PsiClassType exceptionType, + PsiFile file) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory(); if (tryStatement.getTryBlock() == null) { @@ -108,9 +112,12 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { } PsiParameter[] parameters = tryStatement.getCatchBlockParameters(); - parameters[parameters.length - 1].getTypeElement().replace(factory.createTypeElement(exceptionType)); - PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + PsiTypeElement typeElement = parameters[parameters.length - 1].getTypeElement(); + if (typeElement != null) { + JavaCodeStyleManager.getInstance(file.getProject()).shortenClassReferences(typeElement); + } + PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); return catchBlocks[catchBlocks.length - 1]; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java index 19a4639a0689..69800e5616f7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java @@ -200,7 +200,7 @@ public class StaticImportMethodFix implements IntentionAction { //do not show methods from default package && !((PsiJavaFile)file).getPackageName().isEmpty() && PsiUtil.isAccessible(file.getProject(), method, element, containingClass)) { - if (method.isDeprecated()) { + if (isEffectivelyDeprecated(method)) { deprecated.put(containingClass, method); return processCondition(); } @@ -209,6 +209,20 @@ public class StaticImportMethodFix implements IntentionAction { return processCondition(); } + private boolean isEffectivelyDeprecated(PsiMethod method) { + if (method.isDeprecated()) { + return true; + } + PsiClass aClass = method.getContainingClass(); + while (aClass != null) { + if (aClass.isDeprecated()) { + return true; + } + aClass = aClass.getContainingClass(); + } + return false; + } + private boolean processCondition() { return (applicableList.isEmpty() ? list : applicableList).size() + deprecated.size() < 50; } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java index 2b839b5dfcde..daf5aa5eac74 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java @@ -26,13 +26,11 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.intention.AddAnnotationFix; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; -import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -49,22 +47,11 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction { // include not in project files @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - CaretModel caretModel = editor.getCaretModel(); - int position = caretModel.getOffset(); - PsiElement element = file.findElementAt(position); - return element != null && isAvailable(project, element); - } - - public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement element) { - if (!element.isValid()) return false; - final PsiModifierListOwner owner; - if (!element.getManager().isInProject(element) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { - owner = AddAnnotationPsiFix.getContainer(element); - } - else { + final PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(file, editor.getCaretModel().getOffset()); + if (owner == null || + owner.getManager().isInProject(owner) && !CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { return false; } - if (owner == null) return false; Pair annotations = getAnnotations(project); String toAdd = annotations.first; String[] toRemove = annotations.second; @@ -82,11 +69,7 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction { @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - CaretModel caretModel = editor.getCaretModel(); - int position = caretModel.getOffset(); - PsiElement element = file.findElementAt(position); - - PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(element); + PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(file, editor.getCaretModel().getOffset()); if (owner == null || !owner.isValid()) return; Pair annotations = getAnnotations(project); String toAdd = annotations.first; diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java index 7040347c4d0e..767077b3448e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java @@ -28,7 +28,6 @@ import com.intellij.openapi.ui.InputValidatorEx; import com.intellij.openapi.ui.Messages; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -48,22 +47,15 @@ public class EditContractIntention extends BaseIntentionAction { @Nullable private static PsiMethod getTargetMethod(@NotNull Project project, Editor editor, PsiFile file) { - PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); - if (element == null) return null; - if (!element.getManager().isInProject(element) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { - final PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(element); - if (owner instanceof PsiMethod) { - PsiElement original = owner.getOriginalElement(); - if (original instanceof PsiMethod) { - return (PsiMethod)original; - } - return (PsiMethod)owner; - } + final PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(file, editor.getCaretModel().getOffset()); + if (owner instanceof PsiMethod && + (!owner.getManager().isInProject(owner) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS)) { + PsiElement original = owner.getOriginalElement(); + return original instanceof PsiMethod ? (PsiMethod)original : (PsiMethod)owner; } return null; } - @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { final PsiMethod method = getTargetMethod(project, editor, file); diff --git a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java index ee207fb89fc7..a32dc464f7fa 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtil; @@ -187,27 +188,28 @@ public class ChangeClassSignatureProcessor extends BaseRefactoringProcessor { ChangeSignatureUtil.synchronizeList(myClass.getTypeParameterList(), newTypeParameters, TypeParameterList.INSTANCE, toRemoveParms); } - private boolean[] detectRemovedParameters(final PsiTypeParameter[] originaltypeParameters) { - final boolean[] toRemoveParms = new boolean[originaltypeParameters.length]; - Arrays.fill(toRemoveParms, true); + private boolean[] detectRemovedParameters(final PsiTypeParameter[] original) { + final boolean[] toRemove = new boolean[original.length]; + Arrays.fill(toRemove, true); for (final TypeParameterInfo info : myNewSignature) { int oldParameterIndex = info.getOldParameterIndex(); if (oldParameterIndex >= 0) { - toRemoveParms[oldParameterIndex] = false; + toRemove[oldParameterIndex] = false; } } - return toRemoveParms; + return toRemove; } - private void processUsage(final UsageInfo usage, final PsiTypeParameter[] originalTypeParameters, final boolean[] toRemoveParms) - throws IncorrectOperationException { + private void processUsage(UsageInfo usage, PsiTypeParameter[] original, boolean[] toRemove) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)usage.getElement(); + assert referenceElement != null : usage; PsiSubstitutor usageSubstitutor = determineUsageSubstitutor(referenceElement); PsiReferenceParameterList referenceParameterList = referenceElement.getParameterList(); + assert referenceParameterList != null : referenceElement; PsiTypeElement[] oldValues = referenceParameterList.getTypeParameterElements(); - if (oldValues.length != originalTypeParameters.length) return; + if (oldValues.length != original.length) return; List newValues = new ArrayList(); for (final TypeParameterInfo info : myNewSignature) { int oldIndex = info.getOldParameterIndex(); @@ -221,7 +223,9 @@ public class ChangeClassSignatureProcessor extends BaseRefactoringProcessor { newValues.add(newValue); } } - ChangeSignatureUtil.synchronizeList(referenceParameterList, newValues, ReferenceParameterList.INSTANCE, toRemoveParms); + + ChangeSignatureUtil.synchronizeList(referenceParameterList, newValues, ReferenceParameterList.INSTANCE, toRemove); + JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(referenceParameterList); } private PsiSubstitutor determineUsageSubstitutor(PsiJavaCodeReferenceElement referenceElement) { diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java index 25a9481259d8..2b483ddb676c 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; @@ -259,9 +260,13 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor { new InlineToAnonymousConstructorProcessor(myClass, psiNewExpression, superType).run(); } else { - PsiJavaCodeReferenceElement element = - JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory().createClassReferenceElement(superType.resolve()); - psiNewExpression.getClassReference().replace(element); + PsiClass target = superType.resolve(); + assert target != null : superType; + PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); + PsiJavaCodeReferenceElement element = factory.createClassReferenceElement(target); + PsiJavaCodeReferenceElement reference = psiNewExpression.getClassReference(); + assert reference != null : psiNewExpression; + reference.replace(element); } } catch (IncorrectOperationException e) { @@ -276,7 +281,8 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor { PsiType substType = classResolveResult.getSubstitutor().substitute(superType); assert classResolveResult.getElement() == myClass; try { - typeElement.replace(factory.createTypeElement(substType)); + PsiElement replaced = typeElement.replace(factory.createTypeElement(substType)); + JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(replaced); } catch(IncorrectOperationException e) { LOG.error(e); diff --git a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.java index f2a6a2e647a2..ec1e10df935b 100644 --- a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,21 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * User: anna - * Date: 27-Aug-2008 - */ package com.intellij.refactoring.inlineSuperClass.usageInfo; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.util.FixableUsageInfo; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +/** + * @author anna + * @since 27-Aug-2008 + */ public class ReplaceWithSubtypeUsageInfo extends FixableUsageInfo { public static final Logger LOG = Logger.getInstance("#" + ReplaceWithSubtypeUsageInfo.class.getName()); private final PsiTypeElement myTypeElement; @@ -51,8 +52,10 @@ public class ReplaceWithSubtypeUsageInfo extends FixableUsageInfo { public void fixUsage() throws IncorrectOperationException { if (myTypeElement.isValid()) { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myTypeElement.getProject()).getElementFactory(); - myTypeElement.replace(elementFactory.createTypeElement(myTargetClassType)); + Project project = myTypeElement.getProject(); + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); + PsiElement replaced = myTypeElement.replace(elementFactory.createTypeElement(myTargetClassType)); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced); } } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java index 59c7d6505859..9dcd88a9632e 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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,18 @@ import com.intellij.psi.SdkResolveScopeProvider; import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class JavaSourceFilterScope extends DelegatingGlobalSearchScope { + @Nullable private final ProjectFileIndex myIndex; public JavaSourceFilterScope(@NotNull final GlobalSearchScope delegate) { super(delegate); - myIndex = ProjectRootManager.getInstance(getProject()).getFileIndex(); + + Project project = getProject(); + myIndex = project != null ? ProjectRootManager.getInstance(project).getFileIndex() + : null; } @Override @@ -45,6 +50,10 @@ public class JavaSourceFilterScope extends DelegatingGlobalSearchScope { return false; } + if (myIndex == null) { + return false; + } + if (JavaClassFileType.INSTANCE == file.getFileType()) { return myIndex.isInLibraryClasses(file); } diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index 8c36cfae1b88..577d38a30a15 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -519,6 +519,14 @@ public class GenericsUtil { else if (type instanceof PsiArrayType) { return checkNotAssignable(bound, type, true); } + else if (type instanceof PsiIntersectionType) { + for (PsiType psiType : ((PsiIntersectionType)type).getConjuncts()) { + if (!checkNotInBounds(psiType, bound, uncheckedConversionByDefault)) { + return false; + } + } + return true; + } return false; } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java index 215bb86b2b81..5f5d6d7ef8dc 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java @@ -78,7 +78,8 @@ public class PsiIntersectionType extends PsiType { for (PsiType existing : array) { if (type != existing) { final boolean allowUncheckedConversion = type instanceof PsiClassType && ((PsiClassType)type).isRaw(); - if (TypeConversionUtil.isAssignable(type, existing, allowUncheckedConversion)) { + if (TypeConversionUtil.isAssignable(GenericsUtil.eliminateWildcards(type), + GenericsUtil.eliminateWildcards(existing), allowUncheckedConversion)) { iterator.remove(); break; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 0de45be17786..77fd0081d161 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -493,6 +493,13 @@ public class PsiImplUtil { return PsiUtil.captureToplevelWildcards(type, expression); } + final PsiElement parent = toplevel.getParent(); + if (parent instanceof PsiExpressionList && + PsiUtil.isLanguageLevel8OrHigher(parent) && + parent.getParent() instanceof PsiCallExpression) { + return PsiUtil.captureToplevelWildcards(type, expression); + } + final PsiType normalized = doNormalizeWildcardByPosition(type, expression, toplevel); LOG.assertTrue(normalized.isValid(), type); if (normalized instanceof PsiClassType && !PsiUtil.isAccessedForWriting(toplevel)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java index 599f756adbc1..16d971238684 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java @@ -17,8 +17,7 @@ package com.intellij.psi.impl.compiled; import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.util.NotNullLazyValue; -import com.intellij.openapi.util.NullableLazyValue; -import com.intellij.openapi.util.VolatileNullableLazyValue; +import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.PsiJavaParserFacadeImpl; @@ -28,7 +27,6 @@ import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.TreeElement; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement { @NonNls static final char VARIANCE_NONE = '\0'; @@ -41,18 +39,18 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement private final PsiElement myParent; private final String myTypeText; private final char myVariance; - private final NullableLazyValue myChild; + private final NotNullLazyValue> myChild; private final NotNullLazyValue myCachedType; public ClsTypeElementImpl(@NotNull PsiElement parent, @NotNull String typeText, char variance) { myParent = parent; myTypeText = TypeInfo.internFrequentType(typeText); myVariance = variance; - myChild = new VolatileNullableLazyValue() { - @Nullable + myChild = new AtomicNotNullLazyValue>() { + @NotNull @Override - protected ClsElementImpl compute() { - return calculateChild(); + protected Ref compute() { + return Ref.create(calculateChild()); } }; myCachedType = new AtomicNotNullLazyValue() { @@ -67,7 +65,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement @Override @NotNull public PsiElement[] getChildren() { - ClsElementImpl child = myChild.getValue(); + ClsElementImpl child = myChild.getValue().get(); return child != null ? new PsiElement[]{child} : PsiElement.EMPTY_ARRAY; } @@ -111,7 +109,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException { setMirrorCheckingType(element, JavaElementType.TYPE); - ClsElementImpl child = myChild.getValue(); + ClsElementImpl child = myChild.getValue().get(); if (child != null) { child.setMirror(element.getFirstChildNode()); } @@ -157,7 +155,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement PsiType result = PsiJavaParserFacadeImpl.getPrimitiveType(myTypeText); if (result != null) return result; - ClsElementImpl childElement = myChild.getValue(); + ClsElementImpl childElement = myChild.getValue().get(); if (childElement instanceof ClsTypeElementImpl) { if (isArray()) { switch (myVariance) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java index a52ea73a18d5..f1439e6a219d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqualityConstraint; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; @@ -119,14 +118,10 @@ public class FunctionalInterfaceParameterizationUtil { return null; } - if (!TypeConversionUtil.containsWildcards(parameterization)) { + if (!TypeConversionUtil.containsWildcards(parameterization) && psiClassType.isAssignableFrom(parameterization)) { return parameterization; } - if (!psiClassType.isAssignableFrom(parameterization)) { - return null; - } - return getNonWildcardParameterization((PsiClassType)psiClassType); } return null; @@ -169,27 +164,32 @@ public class FunctionalInterfaceParameterizationUtil { for (int i = 0; i < parameters.length; i++) { PsiType paramType = parameters[i]; if (paramType instanceof PsiWildcardType) { - final PsiClassType[] extendsListTypes = typeParameters[i].getExtendsListTypes(); - final PsiClassType Bi = extendsListTypes.length > 0 ? extendsListTypes[0] - : PsiType.getJavaLangObject(psiClass.getManager(), - GlobalSearchScope.allScope(psiClass.getProject())); - if (PsiPolyExpressionUtil.mentionsTypeParameters(Bi, typeParametersSet)) { - return null; + final PsiType bound = GenericsUtil.eliminateWildcards(((PsiWildcardType)paramType).getBound(), false); + if (((PsiWildcardType)paramType).isSuper()) { + newParameters[i] = bound; } - - final PsiType bound = ((PsiWildcardType)paramType).getBound(); - if (bound == null) { - newParameters[i] = Bi; - } else if (((PsiWildcardType)paramType).isExtends()){ - newParameters[i] = GenericsUtil.getGreatestLowerBound(Bi, GenericsUtil.eliminateWildcards(bound, false)); - } else { - newParameters[i] = GenericsUtil.eliminateWildcards(bound, false); + else { + newParameters[i] = bound != null ? bound : PsiType.getJavaLangObject(psiClass.getManager(), psiClassType.getResolveScope()); + for (PsiClassType paramBound : typeParameters[i].getExtendsListTypes()) { + if (!PsiPolyExpressionUtil.mentionsTypeParameters(paramBound, typeParametersSet)) { + newParameters[i] = GenericsUtil.getGreatestLowerBound(paramBound, newParameters[i]); + } + } } } else { newParameters[i] = paramType; } } - return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + + if (!isWellFormed(psiClass, typeParameters, newParameters)) { + return null; + } + + final PsiClassType parameterization = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + if (!psiClassType.isAssignableFrom(parameterization)) { + return null; + } + return parameterization; } return null; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index d46d56d7d96c..727352e5e972 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -20,7 +20,6 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.resolve.graphInference.constraints.*; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.search.GlobalSearchScope; @@ -360,16 +359,11 @@ public class InferenceSession { } return sameMethodCall; } - - public void addCapturedVariable(PsiTypeParameter param) { - initBounds(param); - } private void initReturnTypeConstraint(PsiMethod method, final PsiCallExpression context) { if (PsiPolyExpressionUtil.isMethodCallPolyExpression(context, method)) { PsiType returnType = method.getReturnType(); if (!PsiType.VOID.equals(returnType) && returnType != null) { - returnType = PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context); PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context); if (targetType == null) { targetType = getTargetType(context); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index dcfd45104a25..8db944aaf904 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -129,7 +129,11 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm final PsiParameter[] parameters = method.getParameterList().getParameters(); callSession.initExpressionConstraints(parameters, args, myExpression, method); } - callSession.registerConstraints(returnType, myT); + final boolean accepted = callSession.repeatInferencePhases(true); + if (!accepted) { + //todo return false; + } + callSession.registerConstraints(returnType, substitutor.substitute(returnType)); if (callSession.repeatInferencePhases(true)) { final Collection inferenceVariables = callSession.getInferenceVariables(); if (sameMethodCall) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java index 58c29706c1a3..18ff2d110ad9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java @@ -25,7 +25,6 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiUtil; import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,18 +54,19 @@ public class JavaSharedImplUtil { return type; } + // collects annotations bound to C-style arrays private static List collectAnnotations(PsiElement anchor, PsiAnnotation stopAt) { - List annotations = new SmartList(); + List annotations = ContainerUtil.newSmartList(); List current = null; - boolean stop = false; + boolean found = (stopAt == null), stop = false; for (PsiElement child = anchor.getNextSibling(); child != null; child = child.getNextSibling()) { if (child instanceof PsiComment || child instanceof PsiWhiteSpace) continue; if (child instanceof PsiAnnotation) { - if (current == null) current = new SmartList(); + if (current == null) current = ContainerUtil.newSmartList(); current.add((PsiAnnotation)child); - if (child == stopAt) stop = true; + if (child == stopAt) found = stop = true; continue; } @@ -80,8 +80,8 @@ public class JavaSharedImplUtil { } } - // stop == true means annotation is misplaced - return stop ? null : annotations; + // annotation is misplaced (either located before the anchor or has no following brackets) + return !found || stop ? null : annotations; } public static void normalizeBrackets(@NotNull PsiVariable variable) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java index 506accd112c3..d0d4dbc5324a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java @@ -27,7 +27,7 @@ class UnsupportedFeatures { for (String s : args) { System.out.println(s); } List list = - new ArrayList<>(); + new ArrayList<>(); for (String s : list) {} Arrays.asList(""); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java index 400a678da1ed..28035c8c1698 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java @@ -111,6 +111,7 @@ class Outer { int @TA [] a @TA [] @TA = (p != null ? p : mixedArrays); return a; } + void @TA misplaced() { } @TA Outer() { } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java index 7556292ef538..298a33dcbdf6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java @@ -142,7 +142,7 @@ class S1 { } void bar(List k) { - f(k, k.get(0)); + f(k, k.get(0)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/LiftedCaptureToOuterCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/LiftedCaptureToOuterCall.java new file mode 100644 index 000000000000..75d3b8ab6123 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/LiftedCaptureToOuterCall.java @@ -0,0 +1,16 @@ +class Test { + + class Foo {} + + void test(Foo p) { + foo(bar(p)) ; + } + + T bar(Foo p) { + return null; + } + + K foo(K p) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/LambdaFormalParamTypesParametrization.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/LambdaFormalParamTypesParametrization.java new file mode 100644 index 000000000000..0dbcc3e35fec --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/LambdaFormalParamTypesParametrization.java @@ -0,0 +1,10 @@ +import java.util.function.Function; + +class Test { + + void foo(Function m) {} + + { + foo((String e) -> e.length()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java new file mode 100644 index 000000000000..fa9df550e936 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java @@ -0,0 +1,108 @@ +import java.util.List; + +class SimpleDependency { + + interface I { + R m(); + } + + { + I k = () -> null; + I k1 = () -> null; + I, List> k2 = () -> null; + I, ? extends List> k3 = () -> null; + I, ? extends List> k4 = () -> null; + I, List> k5 = () -> null; + I, ? extends List> k6 = () -> null; + + I s = () -> null; + I, List> s1 = () -> null; + } +} + +class NoDependency { + interface I { + T m(); + } + + { + I k = () -> null; + } +} + +class ExtendsList { + interface I, T> { + R m(); + } + + { + I n = () -> null; + I n1 = () -> null; + I n2 = () -> null; + + + I, String> e1 = () -> null; + I, ?> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, ? extends String> e4 = () -> null; + + I, ? extends String> s1 = () -> null; + I, String> s2 = () -> null; + } +} + +class MultipleBounds { + interface I & Comparable, T> { + R m(); + } + + interface LC extends List, Comparable {} + + { + I n = () -> null; + + I, ? extends String> e1 = () -> null; + I, ? extends String> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, String> e4 = () -> null; + I, String> e5 = () -> null; + } +} + +class FirstIndependentBound { + interface I & Comparable, T> { + R m(); + } + + interface LC extends List, Comparable {} + + { + I n = () -> null; + + I, ? extends String> e1 = () -> null; + I, ? extends String> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, String> e4 = () -> null; + I, String> e5 = () -> null; + } +} + + +class SecondIndependentBound { + interface I & Comparable, T> { + R m(); + } + + interface LC extends List, Comparable {} + + { + I n = () -> null; + + I, ? extends String> e1 = () -> null; + I, ? extends String> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, String> e4 = () -> null; + I, String> e5 = () -> null; + I, ? extends String> e6 = () -> null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayList.java new file mode 100644 index 000000000000..a9274fd2cbc4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayList.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + List names = persons.stream().map(person -> person.getName()).collect(Collectors.toList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListAndFilter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListAndFilter.java new file mode 100644 index 000000000000..4f625cd9427c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListAndFilter.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + List names = persons.stream().filter(person -> person != null).map(person -> person.getName()).collect(Collectors.toList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSet.java new file mode 100644 index 000000000000..13f274c4cf08 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSet.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + Set names = persons.stream().map(person -> person.getName()).collect(Collectors.toSet()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSetFieldInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSetFieldInitializer.java new file mode 100644 index 000000000000..43e84a057c66 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSetFieldInitializer.java @@ -0,0 +1,16 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + Set names = new HashSet<>(); + void collectNames(List persons){ + names.addAll(persons.stream().map(person -> person.getName()).collect(Collectors.toList())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectLinkedHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectLinkedHashSet.java new file mode 100644 index 000000000000..ce7539d68ecd --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectLinkedHashSet.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + Set names = persons.stream().map(person -> person.getName()).collect(Collectors.toCollection(() -> new LinkedHashSet<>())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSelfCollection.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSelfCollection.java new file mode 100644 index 000000000000..ac40fed1b89c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSelfCollection.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public abstract class Collect implements Collection{ + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + addAll(persons.stream().map(person -> person.getName()).collect(Collectors.toList())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSetParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSetParameter.java new file mode 100644 index 000000000000..da15d53fb48d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSetParameter.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons, Set names){ + names.addAll(persons.stream().map(person -> person.getName()).collect(Collectors.toList())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayList.java new file mode 100644 index 000000000000..c7347a282c02 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayList.java @@ -0,0 +1,18 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + List names = new ArrayList<>(); + for (Person person : persons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListAndFilter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListAndFilter.java new file mode 100644 index 000000000000..bd3bced68548 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListAndFilter.java @@ -0,0 +1,20 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + List names = new ArrayList<>(); + for (Person person : persons) { + if (person != null) { + names.add(person.getName()); + } + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSet.java new file mode 100644 index 000000000000..834f2cf1e93a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSet.java @@ -0,0 +1,18 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + Set names = new HashSet<>(); + for (Person person : persons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSetFieldInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSetFieldInitializer.java new file mode 100644 index 000000000000..5a3cf6f30aa4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSetFieldInitializer.java @@ -0,0 +1,18 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + Set names = new HashSet<>(); + void collectNames(List persons){ + for (Person person : persons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectLinkedHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectLinkedHashSet.java new file mode 100644 index 000000000000..144ecd1e1878 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectLinkedHashSet.java @@ -0,0 +1,18 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + Set names = new LinkedHashSet<>(); + for (Person person : persons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSelfCollection.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSelfCollection.java new file mode 100644 index 000000000000..e5bf275e8995 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSelfCollection.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public abstract class Collect implements Collection{ + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons){ + for (Person person : persons) { + add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSetParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSetParameter.java new file mode 100644 index 000000000000..ea3813ad5ac7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSetParameter.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List persons, Set names){ + for (Person person : persons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java index 231a0cd45c0a..ec8b8dd49284 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java @@ -27,7 +27,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.module.Module; @@ -51,6 +50,7 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.*; +import com.intellij.util.ObjectUtils; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -122,13 +122,7 @@ public class AddAnnotationFixTest extends UsefulTestCase { @NotNull private PsiModifierListOwner getOwner() { - CaretModel caretModel = myFixture.getEditor().getCaretModel(); - int position = caretModel.getOffset(); - PsiElement element = myFixture.getFile().findElementAt(position); - assert element != null; - PsiModifierListOwner container = AddAnnotationPsiFix.getContainer(element); - assert container != null; - return container; + return ObjectUtils.assertNotNull(AddAnnotationPsiFix.getContainer(myFixture.getFile(), myFixture.getCaretOffset())); } private void startListening(@NotNull final List> expectedSequence) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java index 1868d2196d7c..964566fcf5ff 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java @@ -39,6 +39,8 @@ public class AnnotationsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testInapplicable() { doTest(false); } public void testDuplicateAttribute() { doTest(false); } public void testDuplicateTarget() { doTest(false); } + public void testPingPongAnnotationTypesDependencies() { doTest(false);} + public void testClashMethods() { doTest(false);} public void testInvalidPackageAnnotationTarget() { doTest(BASE_PATH + "/" + getTestName(true) + "/package-info.java", false, false); } public void testPackageAnnotationNotInPackageInfo() { doTest(BASE_PATH + "/" + getTestName(true) + "/notPackageInfo.java", false, false); } @@ -46,9 +48,6 @@ public class AnnotationsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testTypeAnnotations() { doTest8(false); } public void testRepeatable() { doTest8(false); } - public void testPingPongAnnotationTypesDependencies() { doTest(false);} - public void testClashMethods() { doTest(false);} - private void doTest(boolean checkWarnings) { setLanguageLevel(LanguageLevel.JDK_1_7); doTest(BASE_PATH + "/" + getTestName(true) + ".java", checkWarnings, false); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java index b50052b71750..80448f9d3a96 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java @@ -368,7 +368,7 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase { public void testAutoImportOfGenericReference() throws Throwable { - @NonNls final String text = "class S {{ new ArrayList<> }}"; + @NonNls final String text = "class S {{ new ArrayList }}"; configureByText(StdFileTypes.JAVA, text); boolean old = CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY; CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = true; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java new file mode 100644 index 000000000000..2e32026af72d --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 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.lambda; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NonNls; + +public class FunctionalTypeWildcardParameterizationTest extends LightDaemonAnalyzerTestCase { + @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization"; + + public void testNonWildcardParametrization() throws Exception { + doTest(); + } + + public void testLambdaFormalParamTypesParametrization() throws Exception { + doTest(); + } + + private void doTest() { + IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable()); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false); + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 0182af2a8689..7cac6170b12e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -160,6 +160,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testLiftedCaptureToOuterCall() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java index c2cef13e6ea8..bfd1de796f90 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java @@ -194,7 +194,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { PsiDirectory psiDirectory = FindInProjectUtil.getPsiDirectory(findModel, myProject); List result = new ArrayList(); final CommonProcessors.CollectProcessor collector = new CommonProcessors.CollectProcessor(result); - FindInProjectUtil.findUsages(findModel, psiDirectory, myProject, true, collector, new FindUsagesProcessPresentation(FindInProjectUtil.setupViewPresentation(true, findModel))); + FindInProjectUtil.findUsages(findModel, psiDirectory, myProject, collector, new FindUsagesProcessPresentation(FindInProjectUtil.setupViewPresentation(true, findModel))); return result; } diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java index fba5b6e5265d..7770c5e4a1f9 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.java @@ -34,6 +34,7 @@ import com.intellij.testFramework.SkipSlowTestLocally; import com.intellij.util.indexing.MapIndexStorage; import com.intellij.util.indexing.StorageException; import com.intellij.util.io.*; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -113,7 +114,7 @@ public class IndexTest extends IdeaTestCase { private PersistentHashMap> createMetaIndex(File metaIndexFile) throws IOException { return new PersistentHashMap>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer>() { @Override - public void save(DataOutput out, Collection value) throws IOException { + public void save(@NotNull DataOutput out, Collection value) throws IOException { DataInputOutputUtil.writeINT(out, value.size()); for (String key : value) { out.writeUTF(key); @@ -121,7 +122,7 @@ public class IndexTest extends IdeaTestCase { } @Override - public Collection read(DataInput in) throws IOException { + public Collection read(@NotNull DataInput in) throws IOException { final int size = DataInputOutputUtil.readINT(in); final List list = new ArrayList(); for (int idx = 0; idx < size; idx++) { diff --git a/java/java-tests/testSrc/com/intellij/index/StringIndex.java b/java/java-tests/testSrc/com/intellij/index/StringIndex.java index a12f58fbf137..7d2dd108ceac 100644 --- a/java/java-tests/testSrc/com/intellij/index/StringIndex.java +++ b/java/java-tests/testSrc/com/intellij/index/StringIndex.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 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.index; import com.intellij.openapi.util.Factory; @@ -28,7 +43,7 @@ public class StringIndex { myIndex.setInputIdToDataKeysIndex(factory); } - public List getFilesByWord(String word) throws StorageException { + public List getFilesByWord(@NotNull String word) throws StorageException { return myIndex.getData(word).toValueList(); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java b/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java index 683a8b02abb0..5f74fa20db0d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java +++ b/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java @@ -50,6 +50,21 @@ public class ModuleChunk { myContainsTests = containsTests; } + public String getPresentableShortName() { + String name = myModules.iterator().next().getName(); + if (myModules.size() > 1) { + name += " and " + (myModules.size() - 1) + " more"; + String fullName = getName(); + if (fullName.length() < name.length()) { + name = fullName; + } + } + if (containsTests()) { + name = "tests of " + name; + } + return name; + } + public String getName() { if (myModules.size() == 1) return myModules.iterator().next().getName(); return StringUtil.join(myModules, GET_NAME, ","); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java index 35de6680ca87..1f4bcfc09f8f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java @@ -79,7 +79,7 @@ public class JavaBuilderUtil { final boolean errorsDetected = Utils.errorsDetected(context); if (!isForcedRecompilationAllJavaModules(context)) { if (context.shouldDifferentiate(chunk)) { - context.processMessage(new ProgressMessage("Checking dependencies... [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Checking dependencies... [" + chunk.getPresentableShortName() + "]")); final Set allCompiledFiles = getAllCompiledFilesContainer(context); final Set allAffectedFiles = getAllAffectedFilesContainer(context); @@ -144,7 +144,7 @@ public class JavaBuilderUtil { } } else { - final String messageText = "Marking " + chunk.getName() + " and direct dependants for recompilation"; + final String messageText = "Marking " + chunk.getPresentableShortName() + " and direct dependants for recompilation"; LOG.info("Non-incremental mode: " + messageText); context.processMessage(new ProgressMessage(messageText)); @@ -172,7 +172,7 @@ public class JavaBuilderUtil { return false; } - context.processMessage(new ProgressMessage("Updating dependency information... [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Updating dependency information... [" + chunk.getPresentableShortName() + "]")); globalMappings.integrate(delta); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java index e104ffd7e630..21818f540cc7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -380,12 +380,12 @@ public class ClassRepr extends Proto { public static DataExternalizer externalizer(final DependencyContext context) { return new DataExternalizer() { @Override - public void save(final DataOutput out, final ClassRepr value) throws IOException { + public void save(@NotNull final DataOutput out, final ClassRepr value) throws IOException { value.save(out); } @Override - public ClassRepr read(final DataInput in) throws IOException { + public ClassRepr read(@NotNull final DataInput in) throws IOException { return new ClassRepr(context, in); } }; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java index b72e5aa18d5b..92359612f034 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,6 +16,7 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -57,12 +58,12 @@ class FieldRepr extends ProtoMember { public static DataExternalizer externalizer(final DependencyContext context) { return new DataExternalizer() { @Override - public void save(final DataOutput out, final FieldRepr value) throws IOException { + public void save(@NotNull final DataOutput out, final FieldRepr value) throws IOException { value.save(out); } @Override - public FieldRepr read(final DataInput in) throws IOException { + public FieldRepr read(@NotNull final DataInput in) throws IOException { return new FieldRepr(context, in); } }; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java index eb94639941ac..560c4cecc0fd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -256,7 +256,7 @@ class IntIntPersistentMultiMaplet extends IntIntMultiMaplet { private static class IntSetExternalizer implements DataExternalizer { @Override - public void save(final DataOutput out, final TIntHashSet value) throws IOException { + public void save(@NotNull final DataOutput out, final TIntHashSet value) throws IOException { final Ref exRef = new Ref(null); value.forEach(new TIntProcedure() { @Override @@ -278,7 +278,7 @@ class IntIntPersistentMultiMaplet extends IntIntMultiMaplet { } @Override - public TIntHashSet read(final DataInput in) throws IOException { + public TIntHashSet read(@NotNull final DataInput in) throws IOException { final TIntHashSet result = new TIntHashSet(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java index d195cbc4fc6f..3dd4d446c99a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -245,14 +245,14 @@ class IntObjectPersistentMultiMaplet extends IntObjectMult } @Override - public void save(final DataOutput out, final Collection value) throws IOException { + public void save(@NotNull final DataOutput out, final Collection value) throws IOException { for (V x : value) { myElementExternalizer.save(out, x); } } @Override - public Collection read(final DataInput in) throws IOException { + public Collection read(@NotNull final DataInput in) throws IOException { final Collection result = myCollectionFactory.create(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java index 7b55ea7aaa29..72ad7557cd0b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -18,6 +18,7 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; @@ -159,12 +160,12 @@ class MethodRepr extends ProtoMember { public static DataExternalizer externalizer(final DependencyContext context) { return new DataExternalizer() { @Override - public void save(final DataOutput out, final MethodRepr value) throws IOException { + public void save(@NotNull final DataOutput out, final MethodRepr value) throws IOException { value.save(out); } @Override - public MethodRepr read(DataInput in) throws IOException { + public MethodRepr read(@NotNull DataInput in) throws IOException { return new MethodRepr(context, in); } }; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java index d94d092b13d1..26a9b7a5756f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -245,14 +245,14 @@ public class ObjectObjectPersistentMultiMaplet extends } @Override - public void save(final DataOutput out, final Collection value) throws IOException { + public void save(@NotNull final DataOutput out, final Collection value) throws IOException { for (V x : value) { myElementExternalizer.save(out, x); } } @Override - public Collection read(final DataInput in) throws IOException { + public Collection read(@NotNull final DataInput in) throws IOException { final Collection result = myCollectionFactory.create(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java index dbdb7a9f1179..af85d75f344f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -18,6 +18,7 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; @@ -280,12 +281,12 @@ class TypeRepr { public static DataExternalizer externalizer(final DependencyContext context) { return new DataExternalizer() { @Override - public void save(final DataOutput out, final AbstractType value) throws IOException { + public void save(@NotNull final DataOutput out, final AbstractType value) throws IOException { value.save(out); } @Override - public AbstractType read(final DataInput in) throws IOException { + public AbstractType read(@NotNull final DataInput in) throws IOException { AbstractType elementType; int level = 0; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java index 8db8bbc11ec4..a6b6bdd143f5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; +import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; @@ -505,12 +506,12 @@ class UsageRepr { public static class AnnotationUsage extends Usage { public static final DataExternalizer elementTypeExternalizer = new DataExternalizer() { @Override - public void save(final DataOutput out, final ElemType value) throws IOException { + public void save(@NotNull final DataOutput out, final ElemType value) throws IOException { DataInputOutputUtil.writeINT(out, value.ordinal()); } @Override - public ElemType read(final DataInput in) throws IOException { + public ElemType read(@NotNull final DataInput in) throws IOException { final int ordinal = DataInputOutputUtil.readINT(in); for (ElemType value : ElemType.values()) { if (value.ordinal() == ordinal) { @@ -699,12 +700,12 @@ class UsageRepr { public static DataExternalizer externalizer(final DependencyContext context) { return new DataExternalizer() { @Override - public void save(final DataOutput out, final Usage value) throws IOException { + public void save(@NotNull final DataOutput out, final Usage value) throws IOException { value.save(out); } @Override - public Usage read(DataInput in) throws IOException { + public Usage read(@NotNull DataInput in) throws IOException { final byte tag = in.readByte(); switch (tag) { case CLASS_USAGE: diff --git a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.java b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.java index c75414079b86..eed818e08567 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -18,6 +18,7 @@ package org.jetbrains.jps.classFilesIndex; import com.intellij.util.io.DataExternalizer; import gnu.trove.TObjectIntHashMap; import gnu.trove.TObjectIntProcedure; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -34,7 +35,7 @@ public class TObjectIntHashMapExternalizer implements DataExternalizer map) throws IOException { + public void save(@NotNull final DataOutput out, final TObjectIntHashMap map) throws IOException { out.writeInt(map.size()); try { map.forEachEntry(new TObjectIntProcedure() { @@ -57,7 +58,7 @@ public class TObjectIntHashMapExternalizer implements DataExternalizer read(final DataInput in) throws IOException { + public TObjectIntHashMap read(@NotNull final DataInput in) throws IOException { final int size = in.readInt(); final TObjectIntHashMap map = new TObjectIntHashMap(size); for (int i = 0; i < size; i++) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java index 4d2b60446b52..1eba7b5f9512 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java +++ b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java @@ -163,7 +163,7 @@ public class ClassFilesIndexStorageBase { private static DataExternalizer> createValueContainerExternalizer(final DataExternalizer valueExternalizer) { return new DataExternalizer>() { @Override - public void save(final DataOutput out, final CompiledDataValueContainer value) throws IOException { + public void save(@NotNull final DataOutput out, final CompiledDataValueContainer value) throws IOException { final TIntObjectHashMap underlying = value.myUnderlying; out.writeInt(underlying.size()); final IOException[] ioException = {null}; @@ -187,7 +187,7 @@ public class ClassFilesIndexStorageBase { } @Override - public CompiledDataValueContainer read(final DataInput in) throws IOException { + public CompiledDataValueContainer read(@NotNull final DataInput in) throws IOException { final TIntObjectHashMap map = new TIntObjectHashMap(); final int size = in.readInt(); for (int i = 0; i < size; i++) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java index fec5e9acccd7..b93a7da728f5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java +++ b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java @@ -53,14 +53,14 @@ public class EnumeratedMethodIncompleteSignature { public static DataExternalizer createDataExternalizer() { return new DataExternalizer() { @Override - public void save(final DataOutput out, final EnumeratedMethodIncompleteSignature value) throws IOException { + public void save(@NotNull final DataOutput out, final EnumeratedMethodIncompleteSignature value) throws IOException { out.writeInt(value.getOwner()); out.writeInt(value.getName()); out.writeBoolean(value.isStatic()); } @Override - public EnumeratedMethodIncompleteSignature read(final DataInput in) throws IOException { + public EnumeratedMethodIncompleteSignature read(@NotNull final DataInput in) throws IOException { return new EnumeratedMethodIncompleteSignature(in.readInt(), in.readInt(), in.readBoolean()); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java index 572433552d65..fa022448ef73 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -20,6 +20,7 @@ import com.intellij.util.SmartList; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.IOUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.incremental.storage.AbstractStateStorage; import org.jetbrains.jps.incremental.storage.PathStringDescriptor; @@ -85,7 +86,7 @@ public class ArtifactOutputToSourceMapping extends AbstractStateStorage value) throws IOException { + public void save(@NotNull DataOutput out, List value) throws IOException { for (SourcePathAndRootIndex pair : value) { IOUtil.writeUTFFast(myBuffer, out, pair.myPath); out.writeInt(pair.getRootIndex()); @@ -93,7 +94,7 @@ public class ArtifactOutputToSourceMapping extends AbstractStateStorage read(DataInput in) throws IOException { + public List read(@NotNull DataInput in) throws IOException { List result = new SmartList(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java index 092b002f2384..af1c974b84a2 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java @@ -74,7 +74,7 @@ public abstract class ClassProcessingBuilder extends ModuleLevelBuilder { final String progress = getProgressMessage(); final boolean shouldShowProgress = !StringUtil.isEmptyOrSpaces(progress); if (shouldShowProgress) { - context.processMessage(new ProgressMessage(progress + " [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage(progress + " [" + chunk.getPresentableShortName() + "]")); } ExitCode exitCode = ExitCode.NOTHING_DONE; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 645cdd648bbb..aa10534dd4a4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -243,7 +243,7 @@ public class JavaBuilder extends ModuleLevelBuilder { // begin compilation round final Mappings delta = pd.dataManager.getMappings().createDelta(); final Callbacks.Backend mappingsCallback = delta.getCallback(); - final OutputFilesSink outputSink = new OutputFilesSink(context, outputConsumer, mappingsCallback, chunk.getName()); + final OutputFilesSink outputSink = new OutputFilesSink(context, outputConsumer, mappingsCallback, chunk.getPresentableShortName()); try { if (hasSourcesToCompile) { final AtomicReference ref = COMPILER_VERSION_INFO.get(context); @@ -264,7 +264,7 @@ public class JavaBuilder extends ModuleLevelBuilder { final DiagnosticSink diagnosticSink = new DiagnosticSink(context); final String chunkName = chunk.getName(); - context.processMessage(new ProgressMessage("Parsing java... [" + chunkName + "]")); + context.processMessage(new ProgressMessage("Parsing java... [" + chunk.getPresentableShortName() + "]")); final int filesCount = files.size(); boolean compiledOk = true; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java index 9d34bbb05366..2d40d9faf1e6 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java @@ -37,19 +37,19 @@ public class CompilerMessage extends BuildMessage { private final long myLine; private final long myColumn; - public CompilerMessage(String compilerName, @NotNull Throwable internalError) { + public CompilerMessage(@NotNull String compilerName, @NotNull Throwable internalError) { this(compilerName, Kind.ERROR, getTextFromThrowable(internalError), null, -1L, -1L, -1L, -1L, -1L); } - public CompilerMessage(String compilerName, Kind kind, String messageText) { + public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText) { this(compilerName, kind, messageText, null, -1L, -1L, -1L, -1L, -1L); } - public CompilerMessage(String compilerName, Kind kind, String messageText, String sourcePath) { + public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, String sourcePath) { this(compilerName, kind, messageText, sourcePath, -1L, -1L, -1L, -1L, -1L); } - public CompilerMessage(String compilerName, Kind kind, String messageText, + public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, @Nullable String sourcePath, long problemBeginOffset, long problemEndOffset, @@ -66,6 +66,7 @@ public class CompilerMessage extends BuildMessage { myColumn = locationColumn; } + @NotNull public String getCompilerName() { return myCompilerName; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java index f467dd27c929..c1c364c22b80 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -18,6 +18,7 @@ package org.jetbrains.jps.incremental.storage; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.IOUtil; import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -31,11 +32,11 @@ import java.io.IOException; public final class FileKeyDescriptor implements KeyDescriptor { private final byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); - public void save(DataOutput out, File value) throws IOException { + public void save(@NotNull DataOutput out, File value) throws IOException { IOUtil.writeUTFFast(buffer, out, value.getPath()); } - public File read(DataInput in) throws IOException { + public File read(@NotNull DataInput in) throws IOException { return new File(IOUtil.readUTFFast(buffer, in)); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java index 2c0516327584..6e8eb8787e00 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -83,13 +83,13 @@ public class OneToManyPathsMapping extends AbstractStateStorage> { private final byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); - public void save(DataOutput out, Collection value) throws IOException { + public void save(@NotNull DataOutput out, Collection value) throws IOException { for (String str : value) { IOUtil.writeUTFFast(myBuffer, out, str); } } - public Collection read(DataInput in) throws IOException { + public Collection read(@NotNull DataInput in) throws IOException { final Set result = new THashSet(FileUtil.PATH_HASHING_STRATEGY); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java index 9955c6a64c83..3ebb148ebb71 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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,7 +113,7 @@ public class TimestampStorage extends AbstractStateStorage { - public void save(DataOutput out, TimestampPerTarget[] value) throws IOException { + public void save(@NotNull DataOutput out, TimestampPerTarget[] value) throws IOException { out.writeInt(value.length); for (TimestampPerTarget target : value) { out.writeInt(target.targetId); @@ -121,7 +121,7 @@ public class TimestampStorage extends AbstractStateStorage DETECTED_LINE_SEPARATOR_KEY = Key.create("DETECTED_LINE_SEPARATOR_KEY"); + + /** + * @return Line separator for this file. + * It is always null for directories and binaries, and possibly null if a separator isn't yet known. + * @see com.intellij.util.LineSeparator + */ public String getDetectedLineSeparator() { return getUserData(DETECTED_LINE_SEPARATOR_KEY); } - public void setDetectedLineSeparator(String separator) { + public void setDetectedLineSeparator(@Nullable String separator) { putUserData(DETECTED_LINE_SEPARATOR_KEY, separator); } } diff --git a/platform/core-api/src/com/intellij/psi/CommonClassNames.java b/platform/core-api/src/com/intellij/psi/CommonClassNames.java index a7b6649666b4..32485e7a9066 100644 --- a/platform/core-api/src/com/intellij/psi/CommonClassNames.java +++ b/platform/core-api/src/com/intellij/psi/CommonClassNames.java @@ -61,6 +61,7 @@ public interface CommonClassNames { @NonNls String JAVA_UTIL_LIST = "java.util.List"; @NonNls String JAVA_UTIL_ARRAY_LIST = "java.util.ArrayList"; @NonNls String JAVA_UTIL_SET = "java.util.Set"; + @NonNls String JAVA_UTIL_HASH_SET = "java.util.HashSet"; @NonNls String JAVA_UTIL_PROPERTIES = "java.util.Properties"; @NonNls String JAVA_UTIL_PROPERTY_RESOURCE_BUNDLE = "java.util.PropertyResourceBundle"; @NonNls String JAVA_UTIL_DATE = "java.util.Date"; diff --git a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java index a94a146ba83a..836ad0c5a924 100644 --- a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java @@ -39,7 +39,7 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw private static final Logger LOG = Logger.getInstance("#com.intellij.psi.search.GlobalSearchScope"); @Nullable private final Project myProject; - protected GlobalSearchScope(Project project) { + protected GlobalSearchScope(@Nullable Project project) { myProject = project; } @@ -49,6 +49,7 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw public abstract boolean contains(@NotNull VirtualFile file); + @Nullable @Override public Project getProject() { return myProject; diff --git a/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java b/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java index b11ff743642e..9fd72279c4f2 100644 --- a/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java +++ b/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java @@ -110,7 +110,7 @@ public class MarkupModelWindow extends UserDataHolderBase implements MarkupModel } @Override - public RangeHighlighter addPersistentLineHighlighter(final int line, final int layer, final TextAttributes textAttributes) { + public RangeHighlighterEx addPersistentLineHighlighter(final int line, final int layer, final TextAttributes textAttributes) { int hostLine = myDocument.injectedToHostLine(line); return myHostModel.addPersistentLineHighlighter(hostLine, layer, textAttributes); } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java index 284ef90e2007..28d8cb447d7c 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java @@ -33,7 +33,7 @@ public interface MarkupModelEx extends MarkupModel { void dispose(); @Nullable - RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes); + RangeHighlighterEx addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes); void fireAttributesChanged(@NotNull RangeHighlighterEx segmentHighlighter, boolean renderersChanged); diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java index d9e5c4bd51bd..a3ac344e23bf 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java @@ -109,7 +109,7 @@ public class EmptyMarkupModel implements MarkupModelEx { } @Override - public RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { + public RangeHighlighterEx addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { return null; } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java index 161254604022..5724189b0110 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java @@ -76,7 +76,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @Override @Nullable - public RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { + public RangeHighlighterEx addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { if (isNotValidLine(lineNumber)) { return null; } diff --git a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index dca89ac7bf8a..08eab82f0dcf 100644 --- a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -70,13 +70,13 @@ public class TodoIndex extends FileBasedIndexExtension } @Override - public void save(final DataOutput out, final TodoIndexEntry value) throws IOException { + public void save(@NotNull final DataOutput out, final TodoIndexEntry value) throws IOException { out.writeUTF(value.pattern); out.writeBoolean(value.caseSensitive); } @Override - public TodoIndexEntry read(final DataInput in) throws IOException { + public TodoIndexEntry read(@NotNull final DataInput in) throws IOException { final String pattern = in.readUTF(); final boolean caseSensitive = in.readBoolean(); return new TodoIndexEntry(pattern, caseSensitive); @@ -106,7 +106,7 @@ public class TodoIndex extends FileBasedIndexExtension private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { if (!file.isInLocalFileSystem()) { return false; // do not index TODOs in library sources } @@ -147,16 +147,19 @@ public class TodoIndex extends FileBasedIndexExtension return myIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public DataExternalizer getValueExternalizer() { return myValueExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; diff --git a/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.java b/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.java index 6273968c678f..903c5c4992be 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -32,7 +32,7 @@ public class DefaultFileTypeSpecificInputFilter implements FileBasedIndex.FileTy } @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return true; } } diff --git a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java index 3cdb853b6d95..6628f3c9225e 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -137,7 +137,7 @@ public abstract class FileBasedIndex implements BaseComponent { * @param project it is guaranteed to return data which is up-to-date withing the project * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist */ - public abstract boolean processAllKeys(@NotNull ID indexId, Processor processor, @Nullable Project project); + public abstract boolean processAllKeys(@NotNull ID indexId, @NotNull Processor processor, @Nullable Project project); public boolean processAllKeys(@NotNull ID indexId, @NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) { return processAllKeys(indexId, processor, scope.getProject()); @@ -156,7 +156,7 @@ public abstract class FileBasedIndex implements BaseComponent { * Author: dmitrylomov */ public interface InputFilter { - boolean acceptInput(VirtualFile file); + boolean acceptInput(@NotNull VirtualFile file); } public interface FileTypeSpecificInputFilter extends InputFilter { diff --git a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.java b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.java index 91d9470bbc61..dc6091964163 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -39,11 +39,14 @@ public abstract class FileBasedIndexExtension { @NotNull public abstract DataIndexer getIndexer(); - + + @NotNull public abstract KeyDescriptor getKeyDescriptor(); - + + @NotNull public abstract DataExternalizer getValueExternalizer(); - + + @NotNull public abstract FileBasedIndex.InputFilter getInputFilter(); public abstract boolean dependsOnFileContent(); diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java index 4ad94f5865fc..3e96882ddea1 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -43,19 +43,19 @@ public class IdIndex extends FileBasedIndexExtension { private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return isIndexable(file.getFileType()); } }; private final DataExternalizer myValueExternalizer = new DataExternalizer() { @Override - public void save(final DataOutput out, final Integer value) throws IOException { + public void save(@NotNull final DataOutput out, final Integer value) throws IOException { out.writeByte(value.intValue()); } @Override - public Integer read(final DataInput in) throws IOException { + public Integer read(@NotNull final DataInput in) throws IOException { return Integer.valueOf(in.readByte()); } }; @@ -107,16 +107,19 @@ public class IdIndex extends FileBasedIndexExtension { return myIndexer; } + @NotNull @Override public DataExternalizer getValueExternalizer() { return myValueExternalizer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; diff --git a/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java b/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java index b0a8673ec6ed..061100b77470 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 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.search; import com.intellij.openapi.fileTypes.FileType; @@ -47,11 +62,13 @@ public class FileTypeIndex extends ScalarIndexExtension return this; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return this; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return this; @@ -73,17 +90,17 @@ public class FileTypeIndex extends ScalarIndexExtension } @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !file.isDirectory(); } @Override - public void save(DataOutput out, FileType value) throws IOException { + public void save(@NotNull DataOutput out, FileType value) throws IOException { myEnumeratorStringDescriptor.save(out, value.getName()); } @Override - public FileType read(DataInput in) throws IOException { + public FileType read(@NotNull DataInput in) throws IOException { String read = myEnumeratorStringDescriptor.read(in); return myFileTypeManager.findFileTypeByName(read); } 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 7c42954efe82..0e95aefcc0bb 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -54,11 +54,13 @@ public class FilenameIndex extends ScalarIndexExtension { return myDataIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -156,7 +158,7 @@ public class FilenameIndex extends ScalarIndexExtension { private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return true; } } diff --git a/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java b/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java index df1550082dd7..38321417c29e 100644 --- a/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java +++ b/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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,6 +17,7 @@ package com.intellij.util.indexing; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; @@ -31,6 +32,7 @@ public abstract class ScalarIndexExtension extends FileBasedIndexExtension VOID_DATA_EXTERNALIZER = new VoidDataExternalizer(); + @NotNull @Override public final DataExternalizer getValueExternalizer() { return VOID_DATA_EXTERNALIZER; @@ -39,12 +41,12 @@ public abstract class ScalarIndexExtension extends FileBasedIndexExtension { @Override - public void save(final DataOutput out, final Void value) throws IOException { + public void save(@NotNull final DataOutput out, final Void value) throws IOException { } @Override @Nullable - public Void read(final DataInput in) throws IOException { + public Void read(@NotNull final DataInput in) throws IOException { return null; } } diff --git a/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.java b/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.java index 128d7d40d4fe..1e111b2d01de 100644 --- a/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.java +++ b/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull; * Date: Feb 18, 2009 */ public abstract class SingleEntryFileBasedIndexExtension extends FileBasedIndexExtension{ + @NotNull @Override public final KeyDescriptor getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; diff --git a/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java b/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java index e38cac95243c..652ea0871215 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java @@ -32,13 +32,17 @@ import javax.swing.*; */ public class StopProcessAction extends DumbAwareAction implements AnAction.TransparentUpdate { - private final ProcessHandler myProcessHandler; + private ProcessHandler myProcessHandler; - public StopProcessAction(@NotNull String text, @Nullable String description, @NotNull ProcessHandler processHandler) { + public StopProcessAction(@NotNull String text, @Nullable String description, @Nullable ProcessHandler processHandler) { super(text, description, AllIcons.Actions.Suspend); myProcessHandler = processHandler; } + public void setProcessHandler(@Nullable ProcessHandler processHandler) { + myProcessHandler = processHandler; + } + @Override public void update(final AnActionEvent e) { update(e.getPresentation(), getTemplatePresentation(), myProcessHandler); @@ -72,7 +76,7 @@ public class StopProcessAction extends DumbAwareAction implements AnAction.Trans stopProcess(myProcessHandler); } - public static void stopProcess(@NotNull ProcessHandler processHandler) { + public static void stopProcess(@Nullable ProcessHandler processHandler) { if (processHandler instanceof KillableProcess && processHandler.isProcessTerminating()) { // process termination was requested, but it's still alive // in this case 'force quit' will be performed @@ -80,11 +84,13 @@ public class StopProcessAction extends DumbAwareAction implements AnAction.Trans return; } - if (processHandler.detachIsDefault()) { - processHandler.detachProcess(); - } - else { - processHandler.destroyProcess(); + if (processHandler != null) { + if (processHandler.detachIsDefault()) { + processHandler.detachProcess(); + } + else { + processHandler.destroyProcess(); + } } } diff --git a/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java b/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java index 4c11fe213535..7bc0e0c595f8 100644 --- a/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java @@ -127,7 +127,7 @@ public class FindInProjectManager { return processor.process(usage); } }; - FindInProjectUtil.findUsages(findModelCopy, psiDirectory, myProject, true, consumer, processPresentation); + FindInProjectUtil.findUsages(findModelCopy, psiDirectory, myProject, consumer, processPresentation); } finally { myIsFindInProgress = false; diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java new file mode 100644 index 000000000000..3650e188a65e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java @@ -0,0 +1,394 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.find.impl; + +import com.intellij.find.FindBundle; +import com.intellij.find.FindModel; +import com.intellij.find.ngrams.TrigramIndex; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectCoreUtil; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.util.text.TrigramBuilder; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileFilter; +import com.intellij.psi.*; +import com.intellij.psi.impl.cache.CacheManager; +import com.intellij.psi.impl.cache.impl.id.IdIndex; +import com.intellij.psi.impl.search.PsiSearchHelperImpl; +import com.intellij.psi.search.*; +import com.intellij.usageView.UsageInfo; +import com.intellij.usages.FindUsagesProcessPresentation; +import com.intellij.usages.UsageLimitUtil; +import com.intellij.usages.impl.UsageViewManagerImpl; +import com.intellij.util.CommonProcessors; +import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; +import gnu.trove.TIntHashSet; +import gnu.trove.TIntIterator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * @author peter + */ +class FindInProjectTask { + private static final int FILES_SIZE_LIMIT = 70 * 1024 * 1024; // megabytes. + private static final int SINGLE_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // megabytes. + private final FindModel myFindModel; + private final Project myProject; + private final PsiManager myPsiManager; + @Nullable private final PsiDirectory myPsiDirectory; + private final FileIndex myFileIndex; + private final Condition myFileMask; + private final ProgressIndicator myProgress; + @Nullable private final Module myModule; + private final Set myLargeFiles = ContainerUtil.newTroveSet(); + private boolean myWarningShown; + + FindInProjectTask(@NotNull final FindModel findModel, + @NotNull final Project project, + @Nullable final PsiDirectory psiDirectory) { + myFindModel = findModel; + myProject = project; + myPsiDirectory = psiDirectory; + myPsiManager = PsiManager.getInstance(project); + + final String moduleName = findModel.getModuleName(); + myModule = moduleName == null ? null : ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Module compute() { + return ModuleManager.getInstance(project).findModuleByName(moduleName); + } + }); + myFileIndex = myModule == null ? + ProjectRootManager.getInstance(project).getFileIndex() : + ModuleRootManager.getInstance(myModule).getFileIndex(); + + final String filter = findModel.getFileFilter(); + final Pattern pattern = FindInProjectUtil.createFileMaskRegExp(filter); + + //noinspection unchecked + myFileMask = pattern == null ? Condition.TRUE : new Condition() { + @Override + public boolean value(VirtualFile file) { + return file != null && pattern.matcher(file.getName()).matches(); + } + }; + + final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); + myProgress = progress != null ? progress : new EmptyProgressIndicator(); + } + + public void findUsages(@NotNull final Processor consumer, @NotNull FindUsagesProcessPresentation processPresentation) { + try { + myProgress.setIndeterminate(true); + myProgress.setText("Scanning indexed files..."); + final Set filesForFastWordSearch = getFilesForFastWordSearch(); + myProgress.setIndeterminate(false); + + searchInFiles(consumer, processPresentation, filesForFastWordSearch); + + myProgress.setIndeterminate(true); + myProgress.setText("Scanning non-indexed files..."); + final Collection otherFiles = collectFilesInScope(filesForFastWordSearch); + myProgress.setIndeterminate(false); + + searchInFiles(consumer, processPresentation, otherFiles); + } + catch (ProcessCanceledException e) { + // fine + } + + if (!myLargeFiles.isEmpty()) { + processPresentation.setLargeFilesWereNotScanned(myLargeFiles); + } + + if (!myProgress.isCanceled()) { + myProgress.setText(FindBundle.message("find.progress.search.completed")); + } + } + + private void searchInFiles(Processor consumer, FindUsagesProcessPresentation processPresentation, Collection psiFiles) { + int i = 0; + long totalFilesSize = 0; + int count = 0; + + for (final PsiFile psiFile : psiFiles) { + final VirtualFile virtualFile = psiFile.getVirtualFile(); + final int index = i++; + if (virtualFile == null) continue; + + long fileLength = UsageViewManagerImpl.getFileLength(virtualFile); + if (fileLength == -1) continue; // Binary or invalid + + if (ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile) && !Registry.is("find.search.in.project.files")) continue; + + if (fileLength > SINGLE_FILE_SIZE_LIMIT) { + myLargeFiles.add(psiFile); + continue; + } + + myProgress.checkCanceled(); + myProgress.setFraction((double)index / psiFiles.size()); + String text = FindBundle.message("find.searching.for.string.in.file.progress", + myFindModel.getStringToFind(), virtualFile.getPresentableUrl()); + myProgress.setText(text); + myProgress.setText2(FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count)); + + int countInFile = FindInProjectUtil.processUsagesInFile(psiFile, myFindModel, consumer); + + count += countInFile; + if (countInFile > 0) { + totalFilesSize += fileLength; + if (totalFilesSize > FILES_SIZE_LIMIT && !myWarningShown) { + myWarningShown = true; + String message = FindBundle.message("find.excessive.total.size.prompt", + UsageViewManagerImpl.presentableSize(totalFilesSize), + ApplicationNamesInfo.getInstance().getProductName()); + UsageLimitUtil.showAndCancelIfAborted(myProject, message, processPresentation.getUsageViewPresentation()); + } + } + } + } + + @NotNull + private Collection collectFilesInScope(@NotNull final Set alreadySearched) { + SearchScope customScope = myFindModel.getCustomScope(); + final GlobalSearchScope globalCustomScope = toGlobal(customScope); + + final boolean skipIndexed = canRelyOnIndices(); + + class EnumContentIterator implements ContentIterator { + final Set myFiles = new LinkedHashSet(); + + @Override + public boolean processFile(@NotNull final VirtualFile virtualFile) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + ProgressManager.checkCanceled(); + if (virtualFile.isDirectory() || !virtualFile.isValid() || + !myFileMask.value(virtualFile) || + (globalCustomScope != null && !globalCustomScope.contains(virtualFile))) { + return; + } + + if (skipIndexed && isCoveredByIdIndex(virtualFile)) { + return; + } + + PsiFile psiFile = myPsiManager.findFile(virtualFile); + if (psiFile != null && !(psiFile instanceof PsiBinaryFile) && !alreadySearched.contains(psiFile)) { + PsiFile sourceFile = (PsiFile)psiFile.getNavigationElement(); + if (sourceFile != null) psiFile = sourceFile; + myFiles.add(psiFile); + } + } + }); + return true; + } + + @NotNull + private Collection getFiles() { + return myFiles; + } + } + + EnumContentIterator iterator = new EnumContentIterator(); + + if (customScope instanceof LocalSearchScope) { + for (VirtualFile file : getLocalScopeFiles((LocalSearchScope)customScope)) { + iterator.processFile(file); + } + } + else if (myPsiDirectory != null) { + myFileIndex.iterateContentUnderDirectory(myPsiDirectory.getVirtualFile(), iterator); + } + else { + boolean success = myFileIndex.iterateContent(iterator); + if (success && globalCustomScope != null && globalCustomScope.isSearchInLibraries()) { + final VirtualFile[] librarySources = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public VirtualFile[] compute() { + OrderEnumerator enumerator = myModule == null ? OrderEnumerator.orderEntries(myProject) : OrderEnumerator.orderEntries(myModule); + return enumerator.withoutModuleSourceEntries().withoutDepModules().getSourceRoots(); + } + }); + iterateAll(librarySources, globalCustomScope, iterator); + } + } + return iterator.getFiles(); + } + + private static boolean isCoveredByIdIndex(VirtualFile file) { + return IdIndex.isIndexable(FileBasedIndexImpl.getFileType(file)) && + ((FileBasedIndexImpl)FileBasedIndex.getInstance()).isIndexingCandidate(file, IdIndex.NAME); + } + + private static boolean iterateAll(@NotNull VirtualFile[] files, @NotNull final GlobalSearchScope searchScope, @NotNull final ContentIterator iterator) { + final FileTypeManager fileTypeManager = FileTypeManager.getInstance(); + final VirtualFileFilter contentFilter = new VirtualFileFilter() { + @Override + public boolean accept(@NotNull final VirtualFile file) { + return file.isDirectory() || + !fileTypeManager.isFileIgnored(file) && !file.getFileType().isBinary() && searchScope.contains(file); + } + }; + for (VirtualFile file : files) { + if (!VfsUtilCore.iterateChildrenRecursively(file, contentFilter, iterator)) return false; + } + return true; + } + + @Nullable + private GlobalSearchScope toGlobal(@Nullable final SearchScope scope) { + if (scope instanceof GlobalSearchScope || scope == null) { + return (GlobalSearchScope)scope; + } + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public GlobalSearchScope compute() { + return GlobalSearchScope.filesScope(myProject, getLocalScopeFiles((LocalSearchScope)scope)); + } + }); + } + + @NotNull + private static Set getLocalScopeFiles(@NotNull LocalSearchScope scope) { + Set files = new LinkedHashSet(); + for (PsiElement element : scope.getScope()) { + PsiFile file = element.getContainingFile(); + if (file != null) { + ContainerUtil.addIfNotNull(files, file.getVirtualFile()); + } + } + return files; + } + + private boolean canRelyOnIndices() { + if (DumbService.isDumb(myProject)) return false; + + if (myFindModel.isRegularExpressions()) return false; + + // a local scope may be over a non-indexed file + if (myFindModel.getCustomScope() instanceof LocalSearchScope) return false; + + String text = myFindModel.getStringToFind(); + if (StringUtil.isEmptyOrSpaces(text)) return false; + + if (TrigramIndex.ENABLED) return !TrigramBuilder.buildTrigram(text).isEmpty(); + + // $ is used to separate words when indexing plain-text files but not when indexing + // Java identifiers, so we can't consistently break a string containing $ characters into words + + return myFindModel.isWholeWordsOnly() && text.indexOf('$') < 0; + } + + + @NotNull + private Set getFilesForFastWordSearch() { + String stringToFind = myFindModel.getStringToFind(); + if (stringToFind.isEmpty() || DumbService.getInstance(myProject).isDumb()) { + return Collections.emptySet(); + } + + SearchScope customScope = myFindModel.getCustomScope(); + GlobalSearchScope scope = myPsiDirectory != null + ? GlobalSearchScopesCore.directoryScope(myPsiDirectory, true) + : myModule != null + ? myModule.getModuleContentScope() + : customScope instanceof GlobalSearchScope + ? (GlobalSearchScope)customScope + : toGlobal(customScope); + if (scope == null) { + scope = ProjectScope.getContentScope(myProject); + } + + final Set resultFiles = new LinkedHashSet(); + + if (TrigramIndex.ENABLED) { + Set keys = ContainerUtil.newTroveSet(); + TIntHashSet trigrams = TrigramBuilder.buildTrigram(stringToFind); + TIntIterator it = trigrams.iterator(); + while (it.hasNext()) { + keys.add(it.next()); + } + + if (!keys.isEmpty()) { + List hits = new ArrayList(); + FileBasedIndex.getInstance().getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); + + for (VirtualFile hit : hits) { + if (myFileMask.value(hit)) { + resultFiles.add(findFile(hit)); + } + } + + return resultFiles; + } + } + + PsiSearchHelperImpl helper = (PsiSearchHelperImpl)PsiSearchHelper.SERVICE.getInstance(myProject); + helper.processFilesWithText(scope, UsageSearchContext.ANY, myFindModel.isCaseSensitive(), stringToFind, new Processor() { + @Override + public boolean process(VirtualFile file) { + if (myFileMask.value(file)) { + ContainerUtil.addIfNotNull(resultFiles, findFile(file)); + } + return true; + } + }); + + // in case our word splitting is incorrect + for (PsiFile file : CacheManager.SERVICE.getInstance(myProject) + .getFilesWithWord(stringToFind, UsageSearchContext.ANY, scope, myFindModel.isCaseSensitive())) { + if (myFileMask.value(file.getVirtualFile())) { + resultFiles.add(file); + } + } + + return resultFiles; + } + + private PsiFile findFile(@NotNull final VirtualFile virtualFile) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiFile compute() { + return myPsiManager.findFile(virtualFile); + } + }); + } + +} diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index 2fefcc9649d4..d788d9c6abe9 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -19,73 +19,54 @@ package com.intellij.find.impl; import com.intellij.BundleBase; import com.intellij.find.*; import com.intellij.find.findInProject.FindInProjectManager; -import com.intellij.find.ngrams.TrigramIndex; import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.progress.util.TooManyUsagesStatus; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectCoreUtil; -import com.intellij.openapi.roots.*; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.util.text.TrigramBuilder; -import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.LocalFileProvider; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; import com.intellij.psi.*; -import com.intellij.psi.impl.cache.CacheManager; -import com.intellij.psi.impl.cache.impl.id.IdIndex; -import com.intellij.psi.search.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.SearchScope; import com.intellij.ui.content.Content; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewManager; import com.intellij.usages.ConfigurableUsageTarget; import com.intellij.usages.FindUsagesProcessPresentation; -import com.intellij.usages.UsageLimitUtil; import com.intellij.usages.UsageViewPresentation; -import com.intellij.usages.impl.UsageViewManagerImpl; -import com.intellij.util.CommonProcessors; import com.intellij.util.Function; import com.intellij.util.PatternUtil; import com.intellij.util.Processor; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.FileBasedIndexImpl; -import gnu.trove.THashSet; -import gnu.trove.TIntHashSet; -import gnu.trove.TIntIterator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; -import java.util.*; +import java.util.List; import java.util.regex.Pattern; public class FindInProjectUtil { private static final int USAGES_PER_READ_ACTION = 100; - private static final int FILES_SIZE_LIMIT = 70 * 1024 * 1024; // megabytes. - private static final int SINGLE_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // megabytes. private FindInProjectUtil() {} @@ -156,34 +137,6 @@ public class FindInProjectUtil { return virtualFile == null ? null : psiManager.findDirectory(virtualFile); } - private static void addFilesUnderDirectory(@NotNull PsiDirectory directory, - @NotNull Collection fileList, - boolean isRecursive, - @Nullable Pattern fileMaskRegExp) { - final PsiElement[] children = directory.getChildren(); - - for (PsiElement child : children) { - if (child instanceof PsiFile && - (fileMaskRegExp == null || - fileMaskRegExp.matcher(((PsiFile)child).getName()).matches() - ) - ) { - PsiFile file = (PsiFile)child; - PsiFile sourceFile = (PsiFile)file.getNavigationElement(); - if (sourceFile != null) file = sourceFile; - fileList.add(file); - } - else if (isRecursive && child instanceof PsiDirectory) { - addFilesUnderDirectory((PsiDirectory)child, fileList, isRecursive, fileMaskRegExp); - } - } - } - - @Nullable - private static Pattern createFileMaskRegExp(@NotNull FindModel findModel) { - final String filter = findModel.getFileFilter(); - return createFileMaskRegExp(filter); - } @Nullable public static Pattern createFileMaskRegExp(@Nullable String filter) { @@ -210,74 +163,12 @@ public class FindInProjectUtil { public static void findUsages(@NotNull FindModel findModel, final PsiDirectory psiDirectory, @NotNull final Project project, - boolean showWarnings, @NotNull final Processor consumer, @NotNull FindUsagesProcessPresentation processPresentation) { - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - - final Collection psiFiles = getFilesToSearchIn(findModel, project, psiDirectory); - try { - final Set largeFiles = new THashSet(); - - int i = 0; - long totalFilesSize = 0; - int count = 0; - final boolean[] warningShown = {false}; - - for (final PsiFile psiFile : psiFiles) { - final VirtualFile virtualFile = psiFile.getVirtualFile(); - final int index = i++; - if (virtualFile == null) continue; - - long fileLength = UsageViewManagerImpl.getFileLength(virtualFile); - if (fileLength == -1) continue; // Binary or invalid - - if (ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile) && !Registry.is("find.search.in.project.files")) continue; - - if (fileLength > SINGLE_FILE_SIZE_LIMIT) { - largeFiles.add(psiFile); - continue; - } - - if (progress != null) { - progress.checkCanceled(); - progress.setFraction((double)index / psiFiles.size()); - String text = FindBundle.message("find.searching.for.string.in.file.progress", - findModel.getStringToFind(), virtualFile.getPresentableUrl()); - progress.setText(text); - progress.setText2(FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count)); - } - - int countInFile = processUsagesInFile(psiFile, findModel, consumer); - - count += countInFile; - if (countInFile > 0) { - totalFilesSize += fileLength; - if (totalFilesSize > FILES_SIZE_LIMIT && !warningShown[0]) { - warningShown[0] = true; - String message = FindBundle.message("find.excessive.total.size.prompt", - UsageViewManagerImpl.presentableSize(totalFilesSize), - ApplicationNamesInfo.getInstance().getProductName()); - UsageLimitUtil.showAndCancelIfAborted(project, message, processPresentation.getUsageViewPresentation()); - } - } - } - - - if (!largeFiles.isEmpty()) { - processPresentation.setLargeFilesWereNotScanned(largeFiles); - } - } - catch (ProcessCanceledException e) { - // fine - } - - if (progress != null && !progress.isCanceled()) { - progress.setText(FindBundle.message("find.progress.search.completed")); - } + new FindInProjectTask(findModel, project, psiDirectory).findUsages(consumer, processPresentation); } - private static int processUsagesInFile(@NotNull final PsiFile psiFile, + static int processUsagesInFile(@NotNull final PsiFile psiFile, @NotNull final FindModel findModel, @NotNull final Processor consumer) { if (findModel.getStringToFind().isEmpty()) { @@ -317,279 +208,6 @@ public class FindInProjectUtil { return count; } - private static PsiFile findFile(@NotNull final PsiManager psiManager, @NotNull final VirtualFile virtualFile) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiFile compute() { - return psiManager.findFile(virtualFile); - } - }); - } - - @NotNull - private static Collection getFilesToSearchIn(@NotNull final FindModel findModel, - @NotNull final Project project, - final PsiDirectory psiDirectory) { - final String moduleName = findModel.getModuleName(); - final Module module = moduleName == null ? null : ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Module compute() { - return ModuleManager.getInstance(project).findModuleByName(moduleName); - } - }); - final FileIndex fileIndex = module == null ? - ProjectRootManager.getInstance(project).getFileIndex() : - ModuleRootManager.getInstance(module).getFileIndex(); - - if (psiDirectory == null || findModel.isWithSubdirectories() && fileIndex.isInContent(psiDirectory.getVirtualFile())) { - final Pattern fileMaskRegExp = createFileMaskRegExp(findModel); - // optimization - Pair> fastWords = getFilesForFastWordSearch(findModel, project, psiDirectory, fileMaskRegExp, module, fileIndex); - final Collection filesForFastWordSearch = fastWords.getSecond(); - - final boolean useIdIndex = fastWords.getFirst() && canOptimizeForFastWordSearch(findModel); - - SearchScope customScope = findModel.getCustomScope(); - final GlobalSearchScope globalCustomScope = toGlobal(project, customScope); - - class EnumContentIterator implements ContentIterator { - final Set myFiles = new LinkedHashSet(filesForFastWordSearch); - final PsiManager psiManager = PsiManager.getInstance(project); - - @Override - public boolean processFile(@NotNull VirtualFile virtualFile) { - ProgressManager.checkCanceled(); - if (virtualFile.isDirectory() || - (fileMaskRegExp != null && !fileMaskRegExp.matcher(virtualFile.getName()).matches()) || - (globalCustomScope != null && !globalCustomScope.contains(virtualFile))) { - return true; - } - - if (useIdIndex && isCoveredByIdIndex(virtualFile)) { - return true; - } - - PsiFile psiFile = findFile(psiManager, virtualFile); - if (psiFile != null && !(psiFile instanceof PsiBinaryFile)) { - myFiles.add(psiFile); - } - return true; - } - - @NotNull - private Collection getFiles() { - return myFiles; - } - } - - EnumContentIterator iterator = new EnumContentIterator(); - - if (customScope instanceof LocalSearchScope) { - for (VirtualFile file : getLocalScopeFiles((LocalSearchScope)customScope)) { - iterator.processFile(file); - } - } - - if (psiDirectory == null) { - boolean success = fileIndex.iterateContent(iterator); - if (success && globalCustomScope != null && globalCustomScope.isSearchInLibraries()) { - final VirtualFile[] librarySources = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public VirtualFile[] compute() { - OrderEnumerator enumerator = module == null ? OrderEnumerator.orderEntries(project) : OrderEnumerator.orderEntries(module); - return enumerator.withoutModuleSourceEntries().withoutDepModules().getSourceRoots(); - } - }); - iterateAll(librarySources, globalCustomScope, iterator); - } - } - else { - fileIndex.iterateContentUnderDirectory(psiDirectory.getVirtualFile(), iterator); - } - return iterator.getFiles(); - } - if (psiDirectory.isValid()) { - final Collection fileList = new THashSet(); - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - addFilesUnderDirectory(psiDirectory, fileList, findModel.isWithSubdirectories(), createFileMaskRegExp(findModel)); - } - }); - - return fileList; - } - return Collections.emptyList(); - } - - private static boolean isCoveredByIdIndex(VirtualFile file) { - return IdIndex.isIndexable(FileBasedIndexImpl.getFileType(file)) && - ((FileBasedIndexImpl)FileBasedIndex.getInstance()).isIndexingCandidate(file, IdIndex.NAME); - } - - private static boolean iterateAll(@NotNull VirtualFile[] files, @NotNull final GlobalSearchScope searchScope, @NotNull final ContentIterator iterator) { - final FileTypeManager fileTypeManager = FileTypeManager.getInstance(); - final VirtualFileFilter contentFilter = new VirtualFileFilter() { - @Override - public boolean accept(@NotNull final VirtualFile file) { - return file.isDirectory() || - !fileTypeManager.isFileIgnored(file) && !file.getFileType().isBinary() && searchScope.contains(file); - } - }; - for (VirtualFile file : files) { - if (!VfsUtilCore.iterateChildrenRecursively(file, contentFilter, iterator)) return false; - } - return true; - } - - @Nullable - private static GlobalSearchScope toGlobal(@NotNull final Project project, @Nullable final SearchScope scope) { - if (scope instanceof GlobalSearchScope || scope == null) { - return (GlobalSearchScope)scope; - } - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public GlobalSearchScope compute() { - return GlobalSearchScope.filesScope(project, getLocalScopeFiles((LocalSearchScope)scope)); - } - }); - } - - @NotNull - private static Set getLocalScopeFiles(@NotNull LocalSearchScope scope) { - Set files = new LinkedHashSet(); - for (PsiElement element : scope.getScope()) { - PsiFile file = element.getContainingFile(); - if (file != null) { - ContainerUtil.addIfNotNull(files, file.getVirtualFile()); - } - } - return files; - } - - @NotNull - private static Pair> getFilesForFastWordSearch(@NotNull final FindModel findModel, - @NotNull final Project project, - @Nullable final PsiDirectory psiDirectory, - final Pattern fileMaskRegExp, - @Nullable final Module module, - @NotNull FileIndex fileIndex) { - if (DumbService.getInstance(project).isDumb()) { - return new Pair>(false, Collections.emptyList()); - } - - final PsiManager pm = PsiManager.getInstance(project); - CacheManager cacheManager = CacheManager.SERVICE.getInstance(project); - SearchScope customScope = findModel.getCustomScope(); - GlobalSearchScope scope = psiDirectory != null - ? GlobalSearchScopesCore.directoryScope(psiDirectory, true) - : module != null - ? module.getModuleContentScope() - : customScope instanceof GlobalSearchScope - ? (GlobalSearchScope)customScope - : toGlobal(project, customScope); - if (scope == null) { - scope = ProjectScope.getContentScope(project); - } - - Set keys = new THashSet(30); - final Set resultFiles = new THashSet(); - boolean fast = false; - - String stringToFind = findModel.getStringToFind(); - if (TrigramIndex.ENABLED) { - TIntHashSet trigrams = TrigramBuilder.buildTrigram(stringToFind); - TIntIterator it = trigrams.iterator(); - while (it.hasNext()) { - keys.add(it.next()); - } - - if (!keys.isEmpty()) { - fast = true; - List hits = new ArrayList(); - FileBasedIndex.getInstance().getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); - - for (VirtualFile hit : hits) { - resultFiles.add(findFile(pm, hit)); - } - - filterMaskedFiles(resultFiles, fileMaskRegExp); - if (resultFiles.isEmpty()) return new Pair>(true, resultFiles); - } - } - - - // $ is used to separate words when indexing plain-text files but not when indexing - // Java identifiers, so we can't consistently break a string containing $ characters into words - - fast |= findModel.isWholeWordsOnly() && stringToFind.indexOf('$') < 0; - - List words = StringUtil.getWordsInStringLongestFirst(stringToFind); - - for (int i = 0; i < words.size(); i++) { - String word = words.get(i); - - PsiFile[] files = cacheManager.getFilesWithWord(word, UsageSearchContext.ANY, scope, findModel.isCaseSensitive()); - if (files.length == 0) { - resultFiles.clear(); - break; - } - - final List psiFiles = Arrays.asList(files); - - if (i == 0 && keys.isEmpty()) { - resultFiles.addAll(psiFiles); - } - else { - resultFiles.retainAll(psiFiles); - } - - filterMaskedFiles(resultFiles, fileMaskRegExp); - if (resultFiles.isEmpty()) break; - } - - if (stringToFind.isEmpty()) { - fileIndex.iterateContent(new ContentIterator() { - @Override - public boolean processFile(VirtualFile file) { - if (!file.isDirectory() && fileMaskRegExp.matcher(file.getName()).matches()) { - PsiFile psiFile = findFile(pm, file); - if (psiFile != null) { - resultFiles.add(psiFile); - } - } - return true; - } - }); - } - else { - // in case our word splitting is incorrect - PsiFile[] allWordsFiles = - cacheManager.getFilesWithWord(stringToFind, UsageSearchContext.ANY, scope, findModel.isCaseSensitive()); - ContainerUtil.addAll(resultFiles, allWordsFiles); - - filterMaskedFiles(resultFiles, fileMaskRegExp); - } - - return new Pair>(fast, resultFiles); - } - - private static void filterMaskedFiles(@NotNull final Set resultFiles, @Nullable final Pattern fileMaskRegExp) { - if (fileMaskRegExp != null) { - for (Iterator iterator = resultFiles.iterator(); iterator.hasNext();) { - PsiFile file = iterator.next(); - if (!fileMaskRegExp.matcher(file.getName()).matches()) { - iterator.remove(); - } - } - } - } - - private static boolean canOptimizeForFastWordSearch(@NotNull final FindModel findModel) { - return !findModel.isRegularExpressions() - && (findModel.getCustomScope() == null || findModel.getCustomScope() instanceof GlobalSearchScope); - } - private static int addToUsages(@NotNull Document document, @NotNull Processor consumer, @NotNull FindModel findModel, @NotNull final PsiFile psiFile, @NotNull int[] offsetRef, int maxUsages) { int count = 0; diff --git a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java index 9fdc87e70686..6cf661d2cc6f 100644 --- a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java +++ b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -38,13 +38,13 @@ public class TrigramIndex extends ScalarIndexExtension { private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !file.getFileType().isBinary(); } }; private static final FileBasedIndex.InputFilter NO_FILES = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return false; } }; @@ -76,11 +76,13 @@ public class TrigramIndex extends ScalarIndexExtension { }; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { if (ENABLED) { diff --git a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java index 86fe9de9b5a8..7e220c149369 100644 --- a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java @@ -569,7 +569,7 @@ public class ReplaceInProjectManager { myIsFindInProgress = true; FindInProjectUtil.findUsages(myFindModelCopy, myPsiDirectory, myProject, - true, new AdapterProcessor(processor, UsageInfo2UsageAdapter.CONVERTER), + new AdapterProcessor(processor, UsageInfo2UsageAdapter.CONVERTER), myProcessPresentation); } finally { diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java index 0985d6b43171..dfd6c9c93548 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -141,7 +141,7 @@ public class DetectedFrameworksData { private static class TIntHashSetExternalizer implements DataExternalizer { @Override - public void save(DataOutput out, TIntHashSet value) throws IOException { + public void save(@NotNull DataOutput out, TIntHashSet value) throws IOException { out.writeInt(value.size()); final TIntIterator iterator = value.iterator(); while (iterator.hasNext()) { @@ -150,7 +150,7 @@ public class DetectedFrameworksData { } @Override - public TIntHashSet read(DataInput in) throws IOException { + public TIntHashSet read(@NotNull DataInput in) throws IOException { int size = in.readInt(); final TIntHashSet set = new TIntHashSet(size); while (size-- > 0) { diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java index bc6eba2bba2c..514f0777a638 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -91,11 +91,13 @@ public class FrameworkDetectionIndex extends ScalarIndexExtension { }; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { final Set acceptedTypes = new HashSet(); diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java b/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java new file mode 100644 index 000000000000..a829cf85594f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java @@ -0,0 +1,149 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.scratch; + +import com.intellij.lang.Language; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.ui.ComboboxSpeedSearch; +import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +/** + * @author ignatov + */ +public class CreateScratchFileAction extends AnAction implements DumbAware { + private static final Set FORBIDDEN_LANGUAGES = ContainerUtil.newHashSet("", "$XSLT"); + + public CreateScratchFileAction() { + super("Create Scratch File...", "New Scratch File", null); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = e.getProject(); + if (project == null) return; + + MyDialog dialog = new MyDialog(project); + dialog.setResizable(false); + if (dialog.showAndGet()) { + Language language = dialog.getType(); + VirtualFile file = ScratchpadManager.getInstance(project).createScratchFile(language); + if (file == null) return; + OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file); + FileEditorManager.getInstance(project).openTextEditor(descriptor, true); + } + } + + private static class MyDialog extends DialogWrapper { + @Nullable private Project myProject; + @NotNull private JComboBox myComboBox; + + protected MyDialog(@Nullable Project project) { + super(project); + myProject = project; + setTitle("Specify the Language"); + init(); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + JPanel panel = new JPanel(new BorderLayout()); + myComboBox = createCombo(getLanguages()); + panel.add(myComboBox, BorderLayout.CENTER); + return panel; + } + + @NotNull + public Language getType() { + return ((Language)myComboBox.getSelectedItem()); + } + + @NotNull + private JComboBox createCombo(@NotNull List languages) { + JComboBox jComboBox = new ComboBox(new CollectionComboBoxModel(languages)); + jComboBox.setRenderer(new ListCellRendererWrapper() { + @Override + public void customize(JList list, Language lang, int index, boolean selected, boolean hasFocus) { + if (lang != null) { + setText(lang.getDisplayName()); + LanguageFileType associatedLanguage = lang.getAssociatedFileType(); + if (associatedLanguage != null) setIcon(associatedLanguage.getIcon()); + } + } + }); + new ComboboxSpeedSearch(jComboBox) { + @Override + protected String getElementText(Object element) { + return element instanceof Language ? ((Language)element).getDisplayName() : null; + } + }; + Language previous = myProject != null ? ScratchpadManager.getInstance(myProject).getLatestLanguage() : null; + if (previous != null) { + jComboBox.setSelectedItem(previous); + } + + return jComboBox; + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myComboBox; + } + } + + @NotNull + private static List getLanguages() { + Set result = ContainerUtil.newTreeSet(new Comparator() { + @Override + public int compare(Language l1, Language l2) { + return l1.getDisplayName().compareTo(l2.getDisplayName()); + } + }); + for (Language lang : Language.getRegisteredLanguages()) { + if (!StringUtil.isEmpty(lang.getDisplayName())) result.add(lang); + for (Language dialect : lang.getDialects()) result.add(dialect); + } + return ContainerUtil.filter(result, new Condition() { + @Override + public boolean value(Language lang) { + String name = lang.getDisplayName(); + return !StringUtil.isEmpty(name) && !FORBIDDEN_LANGUAGES.contains(name); + } + }); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadFileSystem.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadFileSystem.java new file mode 100644 index 000000000000..e643b625a7b7 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadFileSystem.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.scratch; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.presentation.Presentation; +import com.intellij.ide.presentation.PresentationProvider; +import com.intellij.lang.Language; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.openapi.vfs.ex.dummy.DummyFileSystem; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.ui.LayeredIcon; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.List; +import java.util.Map; + +public class ScratchpadFileSystem extends DummyFileSystem { + private static final String PROTOCOL = "scratchpad"; + private final Map myCachedFiles = ContainerUtil.newHashMap(); + + public static ScratchpadFileSystem getScratchFileSystem() { + return (ScratchpadFileSystem)VirtualFileManager.getInstance().getFileSystem(PROTOCOL); + } + + public void removeByPrefix(@NotNull final String prefix) { + List toRemove = ContainerUtil.findAll(myCachedFiles.keySet(), new Condition() { + @Override + public boolean value(String s) { + return s.startsWith(prefix); + } + }); + for (String s : toRemove) { + myCachedFiles.remove(s); + } + } + + @Override + public VirtualFile findFileByPath(@NotNull String path) { + VirtualFile file = myCachedFiles.get(path); + if (file != null && file.isValid()) return file; + return null; + } + + @NotNull + public VirtualFile addFile(@NotNull String name, @NotNull Language language, @NotNull String prefix) { + VirtualFile file = new MyLightVirtualFile(name, language, prefix); + myCachedFiles.put(file.getPath(), file); + return file; + } + + @NotNull + @Override + public String getProtocol() { + return PROTOCOL; + } + + @NotNull + @Override + public String extractPresentableUrl(@NotNull String path) { + String substring = StringUtil.substringAfter(path, "/"); + return substring != null ? substring : super.extractPresentableUrl(path); + } + + @Presentation(provider = ScratchPresentation.class) + private static class MyLightVirtualFile extends LightVirtualFile { + private final String myPrefix; + + public MyLightVirtualFile(@NotNull String fileName, @NotNull Language language, @NotNull String projectPrefix) { + super(fileName, language, ""); + myPrefix = projectPrefix; + } + + @NotNull + @Override + public VirtualFileSystem getFileSystem() { + return getScratchFileSystem(); + } + + @NotNull + @Override + public String getPath() { + return myPrefix + super.getPath(); + } + } + + public static class ScratchPresentation extends PresentationProvider { + @Override + public Icon getIcon(@NotNull MyLightVirtualFile file) { + return LayeredIcon.create(file.getFileType().getIcon(), AllIcons.Actions.New); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManager.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManager.java new file mode 100644 index 000000000000..53c988ab198f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManager.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.scratch; + +import com.intellij.lang.Language; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class ScratchpadManager { + public static ScratchpadManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, ScratchpadManager.class); + } + + @NotNull + public abstract VirtualFile createScratchFile(@NotNull Language language); + + @Nullable + public abstract Language getLatestLanguage(); +} diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManagerImpl.java new file mode 100644 index 000000000000..ed931e77f616 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManagerImpl.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.scratch; + +import com.intellij.lang.Language; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class ScratchpadManagerImpl extends ScratchpadManager implements Disposable { + private final Project myProject; + private final Map myExtensionsCounterMap = ContainerUtil.newHashMap(); + private Language myLatestLanguage; + + public ScratchpadManagerImpl(@NotNull Project project) { + myProject = project; + } + + @NotNull + @Override + public VirtualFile createScratchFile(@NotNull final Language language) { + myLatestLanguage = language; + return ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + public VirtualFile compute() { + String name = generateFileName(language); + return ScratchpadFileSystem.getScratchFileSystem().addFile(name, language, calculatePrefix(ScratchpadManagerImpl.this.myProject)); + } + }); + } + + @NotNull + private static String calculatePrefix(@NotNull Project project) { + return project.getLocationHash(); + } + + @Override + public Language getLatestLanguage() { + return myLatestLanguage; + } + + @NotNull + private String generateFileName(@NotNull Language language) { + LanguageFileType associatedFileType = language.getAssociatedFileType(); + String ext = associatedFileType != null ? associatedFileType.getDefaultExtension() : "unknown"; + Integer prev = myExtensionsCounterMap.get(ext); + int updated = prev == null ? 1 : ++prev; + myExtensionsCounterMap.put(ext, updated); + String index = updated == 1 ? "" : updated + "."; + return "scratch." + index + ext; + } + + @Override + public void dispose() { + ScratchpadFileSystem.getScratchFileSystem().removeByPrefix(calculatePrefix(myProject)); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java index 4a94d1ad3781..801887614413 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java @@ -33,6 +33,7 @@ import javax.swing.*; public class EnforcedPlainTextFileTypeFactory extends FileTypeFactory { public static final LayeredIcon ENFORCED_PLAIN_TEXT_ICON = new LayeredIcon(2); + public static final String ENFORCED_PLAIN_TEXT = "Enforced Plain Text"; static { ENFORCED_PLAIN_TEXT_ICON.setIcon(AllIcons.FileTypes.Text, 0); @@ -59,13 +60,13 @@ public class EnforcedPlainTextFileTypeFactory extends FileTypeFactory { @NotNull @Override public String getName() { - return "Enforced Plain Text"; + return ENFORCED_PLAIN_TEXT; } @NotNull @Override public String getDescription() { - return "Enforced Plain Text"; + return ENFORCED_PLAIN_TEXT; } @NotNull diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java index 830681b9ba5e..e8a18e423423 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java @@ -26,9 +26,8 @@ import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; import com.intellij.openapi.roots.ex.ProjectRootManagerEx; import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.util.containers.ConcurrentHashMap; import com.intellij.util.indexing.FileBasedIndex; import org.jetbrains.annotations.NotNull; @@ -45,18 +44,21 @@ import java.util.Map; */ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener { private final Map> myPlainTextFileSets = new ConcurrentHashMap>(); - private final Ref mySetsInitialized = new Ref(false); + private volatile boolean mySetsInitialized = false; + private static final Object LOCK = new Object(); public EnforcedPlainTextFileTypeManager() { ProjectManager.getInstance().addProjectManagerListener(this); } public boolean isMarkedAsPlainText(VirtualFile file) { - if (file instanceof StubVirtualFile || file.isDirectory()) return false; - synchronized (mySetsInitialized) { - if (!mySetsInitialized.get()) { - initPlainTextFileSets(); - mySetsInitialized.set(true); + if (!(file instanceof VirtualFileWithId) || file.isDirectory()) return false; + if (!mySetsInitialized) { + synchronized (LOCK) { + if (!mySetsInitialized) { + initPlainTextFileSets(); + mySetsInitialized = true; + } } } for (Project project : myPlainTextFileSets.keySet()) { @@ -74,7 +76,7 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener } public static boolean isApplicableFor(@NotNull VirtualFile file) { - if (file instanceof StubVirtualFile || file.isDirectory()) return false; + if (!(file instanceof VirtualFileWithId) || file.isDirectory()) return false; FileType originalType = FileTypeManager.getInstance().getFileTypeByFileName(file.getName()); return !originalType.isBinary() && originalType != FileTypes.PLAIN_TEXT && originalType != StdFileTypes.JAVA; } @@ -96,7 +98,7 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener fireRootsChanged(filesToSync, isPlainText); } - private static void fireRootsChanged(final Collection files, final boolean isAdded) { + private void fireRootsChanged(final Collection files, final boolean isAdded) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { @@ -105,6 +107,7 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener ProjectPlainTextFileTypeManager projectPlainTextFileTypeManager = ProjectPlainTextFileTypeManager.getInstance(project); for (VirtualFile file : files) { if (projectPlainTextFileTypeManager.hasProjectContaining(file)) { + ensureProjectFileSetAdded(project, projectPlainTextFileTypeManager); if (isAdded) { projectPlainTextFileTypeManager.addFile(file); } @@ -118,6 +121,13 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener }); } + private void ensureProjectFileSetAdded(@NotNull Project project, + @NotNull ProjectPlainTextFileTypeManager projectPlainTextFileTypeManager) { + if (!myPlainTextFileSets.containsKey(project)) { + myPlainTextFileSets.put(project, projectPlainTextFileTypeManager.getFiles()); + } + } + private static class EnforcedPlainTextFileTypeManagerHolder { private static final EnforcedPlainTextFileTypeManager ourInstance = ServiceManager.getService(EnforcedPlainTextFileTypeManager.class); } diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java index 6cf91fe5a0c0..67b19d6fa54f 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java @@ -19,7 +19,7 @@ import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.util.containers.HashSet; import org.jdom.Attribute; import org.jdom.Element; @@ -37,7 +37,7 @@ public class PersistentFileSetManager implements PersistentStateComponent myFiles = new HashSet(); protected boolean addFile(VirtualFile file) { - if (file instanceof StubVirtualFile || file.isDirectory()) return false; + if (!(file instanceof VirtualFileWithId) || file.isDirectory()) return false; myFiles.add(file); return true; } diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java index cd8c1bf76994..40e1e793a23f 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.checkin; import com.intellij.ide.todo.TodoFilter; import com.intellij.ide.todo.TodoIndexPatternProvider; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.fragments.LineFragment; @@ -302,7 +303,8 @@ public class TodoCheckinHandlerWorker { private static ArrayList getLineFragments(final String fileName, String beforeContent, String afterContent) throws VcsException { try { - DiffFragment[] woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(beforeContent, afterContent); + DiffFragment[] woFormattingBlocks = + DiffPolicy.LINES_WO_FORMATTING.buildFragments(DiffString.create(beforeContent), DiffString.create(afterContent)); DiffFragment[] step1lineFragments = new DiffCorrection.TrueLineBlocks(ComparisonPolicy.IGNORE_SPACE).correctAndNormalize(woFormattingBlocks); return new DiffFragmentsProcessor().process(step1lineFragments); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java index 43bc2facc8a8..bc1254ceca7a 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -108,6 +108,7 @@ public class FileIncludeIndex extends FileBasedIndexExtension getKeyDescriptor() { return new KeyDescriptor() { @@ -122,24 +123,25 @@ public class FileIncludeIndex extends FileBasedIndexExtension> getValueExternalizer() { return new DataExternalizer>() { @Override - public void save(DataOutput out, List value) throws IOException { + public void save(@NotNull DataOutput out, List value) throws IOException { out.writeInt(value.size()); for (FileIncludeInfoImpl info : value) { out.writeUTF(info.path); @@ -150,7 +152,7 @@ public class FileIncludeIndex extends FileBasedIndexExtension read(DataInput in) throws IOException { + public List read(@NotNull DataInput in) throws IOException { int size = in.readInt(); ArrayList infos = new ArrayList(size); for (int i = 0; i < size; i++) { @@ -161,11 +163,12 @@ public class FileIncludeIndex extends FileBasedIndexExtension { @Override - public void save(final DataOutput out, @NotNull final StubIdList value) throws IOException { + public void save(@NotNull final DataOutput out, @NotNull final StubIdList value) throws IOException { int size = value.size(); if (size == 0) { DataInputOutputUtil.writeINT(out, Integer.MAX_VALUE); @@ -183,7 +183,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe @NotNull @Override - public StubIdList read(final DataInput in) throws IOException { + public StubIdList read(@NotNull final DataInput in) throws IOException { int size = DataInputOutputUtil.readINT(in); if (size == Integer.MAX_VALUE) { return new StubIdList(); @@ -428,9 +428,10 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe public void updateIndex(@NotNull StubIndexKey key, int fileId, @NotNull final Map oldValues, @NotNull Map newValues) { try { final MyIndex index = (MyIndex)myIndices.get(key); - index.updateWithMap(fileId, newValues, new Callable>() { + index.updateWithMap(fileId, newValues, new NotNullComputable>() { + @NotNull @Override - public Collection call() throws Exception { + public Collection compute() { return oldValues.keySet(); } }); @@ -449,7 +450,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe @Override public void updateWithMap(final int inputId, @NotNull final Map newData, - @NotNull Callable> oldKeysGetter) throws StorageException { + @NotNull NotNullComputable> oldKeysGetter) throws StorageException { super.updateWithMap(inputId, newData, oldKeysGetter); } } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 93e2b3541f41..4cb07a623f03 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.util.NotNullComputable; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.FileAttribute; @@ -37,7 +38,6 @@ import org.jetbrains.annotations.NotNull; import java.io.*; import java.util.*; -import java.util.concurrent.Callable; /* * @author max @@ -54,13 +54,13 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi private static final DataExternalizer KEY_EXTERNALIZER = new DataExternalizer() { @Override - public void save(final DataOutput out, @NotNull final SerializedStubTree v) throws IOException { + public void save(@NotNull final DataOutput out, @NotNull final SerializedStubTree v) throws IOException { v.write(out); } @NotNull @Override - public SerializedStubTree read(final DataInput in) throws IOException { + public SerializedStubTree read(@NotNull final DataInput in) throws IOException { return new SerializedStubTree(in); } }; @@ -226,11 +226,11 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi @NotNull @Override - public UpdatableIndex createIndexImplementation(final ID indexId, @NotNull final FileBasedIndex owner, @NotNull IndexStorage storage) + public UpdatableIndex createIndexImplementation(@NotNull final ID indexId, @NotNull final FileBasedIndex owner, @NotNull IndexStorage storage) throws StorageException { if (storage instanceof MemoryIndexStorage) { final MemoryIndexStorage memStorage = (MemoryIndexStorage)storage; - memStorage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { + memStorage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() { @Override public void bufferingStateChanged(final boolean newState) { ((StubIndexImpl)StubIndex.getInstance()).setDataBufferingEnabled(newState); @@ -294,7 +294,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi @Override protected void updateWithMap(final int inputId, @NotNull final Map newData, - @NotNull Callable> oldKeysGetter) + @NotNull NotNullComputable> oldKeysGetter) throws StorageException { checkNameStorage(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java index 50e87f85baab..34b7937cb7a1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable; */ public interface AbstractIndex { @NotNull - ValueContainer getData(Key key) throws StorageException; + ValueContainer getData(@NotNull Key key) throws StorageException; - boolean processAllKeys(Processor processor, GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + boolean processAllKeys(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java index 1648f878066c..f888981f21d4 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package com.intellij.util.indexing; import com.intellij.openapi.util.Computable; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Iterator; @@ -72,11 +73,13 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer return getMergedData().size(); } + @NotNull @Override public Iterator getValueIterator() { return getMergedData().getValueIterator(); } + @NotNull @Override public List toValueList() { return getMergedData().toValueList(); @@ -87,11 +90,13 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer return getMergedData().isAssociated(value, inputId); } + @NotNull @Override public IntPredicate getValueAssociationPredicate(Value value) { return getMergedData().getValueAssociationPredicate(value); } + @NotNull @Override public IntIterator getInputIdsIterator(final Value value) { return getMergedData().getInputIdsIterator(value); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java b/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java index 32b22274dced..d504daf8e808 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,6 @@ import org.jetbrains.annotations.NotNull; public abstract class CustomImplementationFileBasedIndexExtension extends FileBasedIndexExtension { @NotNull - public abstract UpdatableIndex createIndexImplementation(final ID indexId, @NotNull FileBasedIndex owner, @NotNull IndexStorage storage) + public abstract UpdatableIndex createIndexImplementation(@NotNull ID indexId, @NotNull FileBasedIndex owner, @NotNull IndexStorage storage) throws StorageException; } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index ed0dd1b19c6b..578529352033 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -252,8 +252,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { myConnection = connection; } - public static boolean isProjectOrWorkspaceFile(final VirtualFile file, - final @Nullable FileType fileType) { + public static boolean isProjectOrWorkspaceFile(@NotNull VirtualFile file, + @Nullable FileType fileType) { if (fileType instanceof InternalFileType) return true; VirtualFile parent = file.isDirectory() ? file: file.getParent(); while(parent instanceof VirtualFileSystemEntry) { @@ -369,8 +369,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { } /** - * @param extension - * @param isCurrentVersionCorrupted * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted */ private boolean registerIndexer(@NotNull final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) @@ -394,7 +392,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return versionChanged; } - private void initIndexStorage(final FileBasedIndexExtension extension, int version, File versionFile) + private void initIndexStorage(@NotNull FileBasedIndexExtension extension, int version, @NotNull File versionFile) throws IOException { MapIndexStorage storage = null; final ID name = extension.getName(); @@ -429,7 +427,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { ids.add(name); } }); - } else { + } + else { myIndicesWithoutFileTypeInfo.add(name); } @@ -545,12 +544,12 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull MemoryIndexStorage storage) throws IOException { final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); - final Ref isBufferingMode = new Ref(false); + final AtomicBoolean isBufferingMode = new AtomicBoolean(); final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); final DataExternalizer> dataExternalizer = new DataExternalizer>() { @Override - public void save(DataOutput out, @NotNull Collection value) throws IOException { + public void save(@NotNull DataOutput out, @NotNull Collection value) throws IOException { try { DataInputOutputUtil.writeINT(out, value.size()); for (K key : value) { @@ -564,7 +563,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull @Override - public Collection read(DataInput in) throws IOException { + public Collection read(@NotNull DataInput in) throws IOException { try { final int size = DataInputOutputUtil.readINT(in); final List list = new ArrayList(size); @@ -621,7 +620,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { } }; - storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { + storage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() { @Override public void bufferingStateChanged(boolean newState) { synchronized (map) { @@ -715,10 +714,11 @@ public class FileBasedIndexImpl extends FileBasedIndex { } @Override - public boolean processAllKeys(@NotNull final ID indexId, Processor processor, @Nullable Project project) { - return processAllKeys(indexId, processor, project != null ? GlobalSearchScope.allScope(project) : new EverythingGlobalScope(), null); + public boolean processAllKeys(@NotNull final ID indexId, @NotNull Processor processor, @Nullable Project project) { + return processAllKeys(indexId, processor, project == null ? new EverythingGlobalScope() : GlobalSearchScope.allScope(project), null); } + @Override public boolean processAllKeys(@NotNull ID indexId, @NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) { try { final UpdatableIndex index = getIndex(indexId); @@ -949,7 +949,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return null; } - private boolean processValuesImpl(@NotNull final ID indexId, final K dataKey, final boolean ensureValueProcessedOnce, + private boolean processValuesImpl(@NotNull final ID indexId, @NotNull final K dataKey, final boolean ensureValueProcessedOnce, @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, @NotNull final GlobalSearchScope scope, @Nullable final IdFilter idFilter) { ThrowableConvertor, Boolean, StorageException> keyProcessor = @@ -1058,6 +1058,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { }); } + @Override public boolean containsFileId(int id) { if (id < myMinId) return false; if (id > myMaxId) return false; @@ -1659,7 +1660,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return (UpdatableIndex)pair.getFirst(); } - private InputFilter getInputFilter(ID indexId) { + private InputFilter getInputFilter(@NotNull ID indexId) { final Pair, InputFilter> pair = myIndices.get(indexId); assert pair != null : "Index data is absent for index " + indexId; @@ -1766,7 +1767,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - public static FileType getFileType(VirtualFile file) { + @NotNull + public static FileType getFileType(@NotNull VirtualFile file) { FileType fileType = file.getFileType(); if (fileType == FileTypes.PLAIN_TEXT && FileTypeManagerImpl.isFileTypeDetectedFromContent(file)) { fileType = FileTypes.UNKNOWN; @@ -1803,7 +1805,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { fc.putUserData(IndexingDataKeys.PROJECT, project); } - private void updateSingleIndex(final ID indexId, @NotNull final VirtualFile file, @Nullable FileContent currentFC) + private void updateSingleIndex(@NotNull ID indexId, @NotNull final VirtualFile file, @Nullable FileContent currentFC) throws StorageException { if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { return; // the index is scheduled for rebuild, no need to update @@ -1823,8 +1825,9 @@ public class FileBasedIndexImpl extends FileBasedIndex { ); } - private Runnable createIndexedStampUpdateRunnable(final ID indexId, - final VirtualFile file, + @NotNull + private Runnable createIndexedStampUpdateRunnable(@NotNull final ID indexId, + @NotNull final VirtualFile file, final boolean hasContent) { return new Runnable() { @Override @@ -1843,7 +1846,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { }; } - private Computable createUpdateComputableWithBufferingDisabled(final Computable update) { + @NotNull + private Computable createUpdateComputableWithBufferingDisabled(@NotNull final Computable update) { return new Computable() { @Override public Boolean compute() { @@ -2080,7 +2084,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { }); } - private void invalidateIndicesForFile(final VirtualFile file, boolean markForReindex) { + private void invalidateIndicesForFile(@NotNull final VirtualFile file, boolean markForReindex) { cleanProcessedFlag(file); IndexingStamp.flushCache(file); @@ -2439,12 +2443,12 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - private boolean shouldIndexFile(final VirtualFile file, final ID indexId) { + private boolean shouldIndexFile(@NotNull VirtualFile file, @NotNull ID indexId) { return getInputFilter(indexId).acceptInput(file) && (isMock(file) || !isFileIndexed(file, indexId)); } - private static boolean isFileIndexed(VirtualFile file, ID indexId) { + private static boolean isFileIndexed(VirtualFile file, @NotNull ID indexId) { return IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); } @@ -2537,7 +2541,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { } @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java index 78814029780c..110db7255f84 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -119,14 +119,15 @@ public class FileBasedIndexProjectHandler extends AbstractProjectComponent imple return myIndex.getNumberOfPendingInvalidations(); } + @NotNull @Override - public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { + public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) { Collection files = myIndex.getFilesToUpdate(myProject); return VfsUtilCore.toVirtualFileArray(files); } @Override - public void processFile(FileContent fileContent) { + public void processFile(@NotNull FileContent fileContent) { myIndex.processRefreshedFile(myProject, fileContent); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.java index 6d168332e8c5..226542e49366 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -47,23 +47,28 @@ public class IndexInfrastructure { private IndexInfrastructure() { } + @NotNull public static File getVersionFile(@NotNull ID indexName) { return new File(getIndexDirectory(indexName, true), indexName + ".ver"); } + @NotNull public static File getStorageFile(@NotNull ID indexName) { return new File(getIndexRootDir(indexName), indexName.toString()); } + @NotNull public static File getInputIndexStorageFile(@NotNull ID indexName) { - return new File(getIndexRootDir(indexName), indexName.toString()+"_inputs"); + return new File(getIndexRootDir(indexName), indexName +"_inputs"); } + @NotNull public static File getIndexRootDir(@NotNull ID indexName) { return getIndexDirectory(indexName, false); } - private static File getIndexDirectory(ID indexName, boolean forVersion) { + @NotNull + private static File getIndexDirectory(@NotNull ID indexName, boolean forVersion) { final String dirName = indexName.toString().toLowerCase(Locale.US); // store StubIndices under StubUpdating index' root to ensure they are deleted // when StubUpdatingIndex version is changed @@ -76,7 +81,7 @@ public class IndexInfrastructure { private static volatile long ourLastStamp; // ensure any file index stamp increases - public static synchronized void rewriteVersion(final File file, final int version) throws IOException { + public static synchronized void rewriteVersion(@NotNull final File file, final int version) throws IOException { final long prevLastModifiedValue = file.lastModified(); if (file.exists()) { FileUtil.delete(file); @@ -108,7 +113,7 @@ public class IndexInfrastructure { } } - public static long getIndexCreationStamp(ID indexName) { + public static long getIndexCreationStamp(@NotNull ID indexName) { Long version = ourIndexIdToCreationStamp.get(indexName); if (version != null) return version.longValue(); @@ -118,7 +123,7 @@ public class IndexInfrastructure { return stamp; } - public static boolean versionDiffers(final File versionFile, final int currentIndexVersion) { + public static boolean versionDiffers(@NotNull File versionFile, final int currentIndexVersion) { try { ourLastStamp = Math.max(ourLastStamp, versionFile.lastModified()); final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(versionFile))); @@ -137,7 +142,7 @@ public class IndexInfrastructure { } @Nullable - public static VirtualFile findFileById(final PersistentFS fs, final int id) { + public static VirtualFile findFileById(@NotNull PersistentFS fs, final int id) { if (ourUnitTestMode) { final VirtualFile testFile = findTestFile(id); if (testFile != null) { @@ -159,7 +164,7 @@ public class IndexInfrastructure { } @Nullable - public static VirtualFile findFileByIdIfCached(final PersistentFS fs, final int id) { + public static VirtualFile findFileByIdIfCached(@NotNull PersistentFS fs, final int id) { if (ourUnitTestMode) { final VirtualFile testFile = findTestFile(id); if (testFile != null) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java index 0f8bb67f00fc..1020876ca2e4 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -33,15 +33,16 @@ public interface IndexStorage extends Flushable { void addValue(Key key, int inputId, Value value) throws StorageException; - void removeAllValues(Key key, int inputId) throws StorageException; + void removeAllValues(@NotNull Key key, int inputId) throws StorageException; void clear() throws StorageException; @NotNull ValueContainer read(Key key) throws StorageException; - boolean processKeys(Processor processor, GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + boolean processKeys(@NotNull Processor processor, GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + @NotNull Collection getKeys() throws StorageException; void close() throws StorageException; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java index ebf6906a0d1c..620b84a29886 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -26,14 +26,19 @@ import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.TObjectLongHashMap; import gnu.trove.TObjectLongProcedure; import gnu.trove.TObjectProcedure; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentMap; /** * @author Eugene Zhuravlev @@ -100,16 +105,17 @@ public class IndexingStamp { } } }); - } else { + } + else { DataInputOutputUtil.writeTIME(stream, DataInputOutputUtil.timeBase); } } - public long get(ID id) { + private long get(ID id) { return myIndexStamps != null? myIndexStamps.get(id) : 0L; } - public void set(ID id, long tmst) { + private void set(ID id, long tmst) { try { if (tmst < 0) { if (myIndexStamps == null) return; @@ -130,9 +136,9 @@ public class IndexingStamp { } } - private static final ConcurrentHashMap myTimestampsCache = new ConcurrentHashMap(); + private static final ConcurrentMap myTimestampsCache = new ConcurrentHashMap(); private static final int CAPACITY = 100; - private static final ArrayBlockingQueue myFinishedFiles = new ArrayBlockingQueue(CAPACITY); + private static final BlockingQueue ourFinishedFiles = new ArrayBlockingQueue(CAPACITY); public static boolean isFileIndexed(VirtualFile file, ID indexName, final long indexCreationStamp) { try { @@ -148,7 +154,7 @@ public class IndexingStamp { return false; } - public static long getIndexStamp(VirtualFile file, ID indexName) { + public static long getIndexStamp(@NotNull VirtualFile file, ID indexName) { synchronized (getStripedLock(file)) { Timestamps stamp = createOrGetTimeStamp(file); if (stamp != null) return stamp.get(indexName); @@ -156,7 +162,7 @@ public class IndexingStamp { } } - private static Timestamps createOrGetTimeStamp(VirtualFile file) { + private static Timestamps createOrGetTimeStamp(@NotNull VirtualFile file) { if (file instanceof NewVirtualFile && file.isValid()) { Timestamps timestamps = myTimestampsCache.get(file); if (timestamps == null) { @@ -174,7 +180,7 @@ public class IndexingStamp { return null; } - public static void update(final VirtualFile file, final ID indexName, final long indexCreationStamp) { + public static void update(@NotNull VirtualFile file, @NotNull ID indexName, final long indexCreationStamp) { synchronized (getStripedLock(file)) { try { Timestamps stamp = createOrGetTimeStamp(file); @@ -185,7 +191,7 @@ public class IndexingStamp { } } - public static void removeAllIndexedState(VirtualFile file) { + public static void removeAllIndexedState(@NotNull VirtualFile file) { synchronized (getStripedLock(file)) { if (file instanceof NewVirtualFile && file.isValid()) { myTimestampsCache.put(file, new Timestamps()); @@ -193,7 +199,8 @@ public class IndexingStamp { } } - public static Collection> getIndexedIds(final VirtualFile file) { + @NotNull + public static Collection> getIndexedIds(@NotNull VirtualFile file) { synchronized (getStripedLock(file)) { try { Timestamps stamp = createOrGetTimeStamp(file); @@ -220,17 +227,11 @@ public class IndexingStamp { } public static void flushCache(@Nullable VirtualFile finishedFile) { - if (finishedFile == null || !myFinishedFiles.offer(finishedFile)) { - VirtualFile[] files = null; - synchronized (myFinishedFiles) { - int size = myFinishedFiles.size(); - if ((finishedFile == null && size > 0) || size == CAPACITY) { - files = myFinishedFiles.toArray(new VirtualFile[size]); - myFinishedFiles.clear(); - } - } + if (finishedFile == null || !ourFinishedFiles.offer(finishedFile)) { + List files = new ArrayList(ourFinishedFiles.size()); + ourFinishedFiles.drainTo(files); - if (files != null) { + if (!files.isEmpty()) { for(VirtualFile file:files) { synchronized (getStripedLock(file)) { Timestamps timestamp = myTimestampsCache.remove(file); @@ -248,7 +249,7 @@ public class IndexingStamp { } } } - if (finishedFile != null) myFinishedFiles.offer(finishedFile); + if (finishedFile != null) ourFinishedFiles.offer(finishedFile); } } @@ -257,7 +258,7 @@ public class IndexingStamp { for(int i = 0; i < ourLocks.length; ++i) ourLocks[i] = new Object(); } - private static Object getStripedLock(VirtualFile file) { + private static Object getStripedLock(@NotNull VirtualFile file) { if (!(file instanceof NewVirtualFile)) return 0; int id = ((NewVirtualFile)file).getId(); return ourLocks[(id & 0xFF) % ourLocks.length]; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java index 649bd25730fb..bbd015507e24 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -60,7 +60,7 @@ public final class MapIndexStorage implements IndexStorage myDataExternalizer; - private boolean myHighKeySelectivity; + private final boolean myHighKeySelectivity; private final LowMemoryWatcher myLowMemoryFlusher = LowMemoryWatcher.register(new Runnable() { @Override public void run() { @@ -70,7 +70,8 @@ public final class MapIndexStorage implements IndexStorage implements IndexStorage valueExternalizer, final int cacheSize, boolean highKeySelectivity, - boolean buildKeyHashToVirtualFileMapping - ) throws IOException { - + boolean buildKeyHashToVirtualFileMapping) throws IOException { myStorageFile = storageFile; myKeyDescriptor = keyDescriptor; myCacheSize = cacheSize; @@ -150,6 +149,7 @@ public final class MapIndexStorage implements IndexStorage implements IndexStorage processor, GlobalSearchScope scope, final IdFilter idFilter) throws StorageException { + public boolean processKeys(@NotNull final Processor processor, GlobalSearchScope scope, final IdFilter idFilter) throws StorageException { l.lock(); try { myCache.clear(); // this will ensure that all new keys are made into the map @@ -298,7 +298,8 @@ public final class MapIndexStorage implements IndexStorage implements IndexStorage implements IndexStorage implements IndexStorage implements IndexStorage, DifferentSerializableBytesImplyNonEqualityPolicy { @Override - public void save(DataOutput out, int[] value) throws IOException { + public void save(@NotNull DataOutput out, int[] value) throws IOException { DataInputOutputUtil.writeINT(out, value[0]); DataInputOutputUtil.writeINT(out, value[1]); } @Override - public int[] read(DataInput in) throws IOException { + public int[] read(@NotNull DataInput in) throws IOException { return new int[] {DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)}; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java index f49f70db83bd..a19e2d92cddf 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.NotNullComputable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.search.GlobalSearchScope; @@ -33,8 +34,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.*; -import java.util.concurrent.Callable; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -146,18 +149,20 @@ public class MapReduceIndex implements UpdatableIndex processor, GlobalSearchScope scope, IdFilter idFilter) throws StorageException { + public boolean processAllKeys(@NotNull Processor processor, @NotNull GlobalSearchScope scope, IdFilter idFilter) throws StorageException { final Lock lock = getReadLock(); try { lock.lock(); @@ -170,7 +175,7 @@ public class MapReduceIndex implements UpdatableIndex getData(final Key key) throws StorageException { + public ValueContainer getData(@NotNull final Key key) throws StorageException { final Lock lock = getReadLock(); try { lock.lock(); @@ -203,6 +208,7 @@ public class MapReduceIndex implements UpdatableIndex update(final int inputId, @Nullable final Input content) { @@ -219,17 +225,24 @@ public class MapReduceIndex implements UpdatableIndex>() { + updateWithMap(inputId, data, new NotNullComputable>() { + @NotNull @Override - public Collection call() throws Exception { + public Collection compute() { if (myInputsIndex == null) { return new SmartList((Key)(Integer)inputId); } - final Collection oldKeys = myInputsIndex.get(inputId); - return oldKeys == null? Collections.emptyList() : oldKeys; + try { + Collection oldKeys = myInputsIndex.get(inputId); + return oldKeys == null? Collections.emptyList() : oldKeys; + } + catch (IOException e) { + throw new RuntimeException(e); + } } }); - } catch (StorageException ex) { + } + catch (StorageException ex) { exRef.set(ex); } } @@ -239,20 +252,19 @@ public class MapReduceIndex implements UpdatableIndex newData, - @NotNull Callable> oldKeysGetter) throws StorageException { + @NotNull NotNullComputable> oldKeysGetter) throws StorageException { getWriteLock().lock(); try { try { - for (Key key : oldKeysGetter.call()) { + for (Key key : oldKeysGetter.compute()) { myStorage.removeAllValues(key, inputId); } } @@ -277,7 +289,8 @@ public class MapReduceIndex implements UpdatableIndex entry : newData.entrySet()) { myStorage.addValue(entry.getKey(), inputId, entry.getValue()); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.java index 3ef7d2ac4e98..2ae474b73858 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -34,6 +34,7 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class MemoryIndexStorage implements IndexStorage { private final Map> myMap = new HashMap>(); + @NotNull private final IndexStorage myBackendStorage; private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final AtomicBoolean myBufferingEnabled = new AtomicBoolean(false); @@ -44,19 +45,20 @@ public class MemoryIndexStorage implements IndexStorage void memoryStorageCleared(); } - public MemoryIndexStorage(IndexStorage backend) { + public MemoryIndexStorage(@NotNull IndexStorage backend) { myBackendStorage = backend; } + @NotNull public IndexStorage getBackendStorage() { return myBackendStorage; } - public void addBufferingStateListsner(BufferingStateListener listener) { + public void addBufferingStateListener(@NotNull BufferingStateListener listener) { myListeners.add(listener); } - public void removeBufferingStateListsner(BufferingStateListener listener) { + public void removeBufferingStateListener(@NotNull BufferingStateListener listener) { myListeners.remove(listener); } @@ -99,6 +101,7 @@ public class MemoryIndexStorage implements IndexStorage myBackendStorage.flush(); } + @NotNull @Override public Collection getKeys() throws StorageException { final Set keys = new HashSet(); @@ -107,7 +110,7 @@ public class MemoryIndexStorage implements IndexStorage } @Override - public boolean processKeys(final Processor processor, GlobalSearchScope scope, IdFilter idFilter) throws StorageException { + public boolean processKeys(@NotNull final Processor processor, GlobalSearchScope scope, IdFilter idFilter) throws StorageException { final Set stopList = new HashSet(); Processor decoratingProcessor = new Processor() { @@ -129,7 +132,7 @@ public class MemoryIndexStorage implements IndexStorage } stopList.add(key); } - return myBackendStorage.processKeys(stopList.size() == 0 && myMap.size() == 0 ? processor : decoratingProcessor, scope, idFilter); + return myBackendStorage.processKeys(stopList.isEmpty() && myMap.isEmpty() ? processor : decoratingProcessor, scope, idFilter); } @Override @@ -147,7 +150,7 @@ public class MemoryIndexStorage implements IndexStorage } @Override - public void removeAllValues(Key key, int inputId) throws StorageException { + public void removeAllValues(@NotNull Key key, int inputId) throws StorageException { if (myBufferingEnabled.get()) { getMemValueContainer(key).removeAssociatedValue(inputId); return; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index 2a18906d80f8..a4975f100d96 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.CollectingContentIterator; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -49,8 +50,9 @@ public class UnindexedFilesUpdater implements CacheUpdater { return myIndex.getNumberOfPendingInvalidations(); } + @NotNull @Override - public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { + public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) { myIndex.filesUpdateStarted(myProject); CollectingContentIterator finder = myIndex.createContentIterator(indicator); long l = System.currentTimeMillis(); @@ -66,10 +68,11 @@ public class UnindexedFilesUpdater implements CacheUpdater { } @Override - public void processFile(final FileContent fileContent) { + public void processFile(@NotNull FileContent fileContent) { try { myIndex.indexFileContent(myProject, fileContent); - } finally { + } + finally { IndexingStamp.flushCache(fileContent.getVirtualFile()); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java index 589db0f47e58..4b431eddb5d7 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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,6 +17,7 @@ package com.intellij.util.indexing; import com.intellij.openapi.util.Computable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.concurrent.locks.Lock; @@ -31,12 +32,13 @@ public interface UpdatableIndex extends AbstractIndex update(int inputId, @Nullable Input content); - + + @NotNull Lock getReadLock(); - + + @NotNull Lock getWriteLock(); void dispose(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java index d901751fadf4..47efe30fbf84 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,6 +16,8 @@ package com.intellij.util.indexing; +import org.jetbrains.annotations.NotNull; + import java.util.Iterator; import java.util.List; @@ -35,15 +37,19 @@ public abstract class ValueContainer { abstract static class IntPredicate { abstract boolean contains(int id); } - + + @NotNull public abstract IntIterator getInputIdsIterator(Value value); public abstract boolean isAssociated(Value value, int inputId); + @NotNull public abstract IntPredicate getValueAssociationPredicate(Value value); + @NotNull public abstract Iterator getValueIterator(); + @NotNull public abstract List toValueList(); public abstract int size(); @@ -53,7 +59,7 @@ public abstract class ValueContainer { boolean perform(int id, T value); } - public final boolean forEach(final ContainerAction action) { + public final boolean forEach(@NotNull ContainerAction action) { for (final Iterator valueIterator = getValueIterator(); valueIterator.hasNext();) { final Value value = valueIterator.next(); for (final IntIterator intIterator = getInputIdsIterator(value); intIterator.hasNext();) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index ae9424d7733e..ddc538154177 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.SmartList; import com.intellij.util.containers.EmptyIterator; import gnu.trove.*; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -139,6 +140,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement return true; } + @NotNull @Override public Iterator getValueIterator() { if (myInputIdMapping != null) { @@ -190,6 +192,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement } } + @NotNull @Override public List toValueList() { if (myInputIdMapping == null) { @@ -216,6 +219,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement return false; } + @NotNull @Override public IntPredicate getValueAssociationPredicate(Value value) { final Object input = getInput(value); @@ -247,6 +251,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement }; } + @NotNull @Override public IntIterator getInputIdsIterator(Value value) { final Object input = getInput(value); @@ -335,6 +340,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement } }; + @NotNull public ValueContainerImpl copy() { ValueContainerImpl container = new ValueContainerImpl(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java index c4385b491733..3bf0ece67a99 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 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.util.indexing; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; @@ -71,7 +86,7 @@ class ValueContainerMap extends PersistentHashMap container) throws IOException { + public void save(@NotNull final DataOutput out, @NotNull final ValueContainer container) throws IOException { saveImpl(out, container); } @@ -79,29 +94,24 @@ class ValueContainerMap extends PersistentHashMap container) throws IOException { + private void saveImpl(@NotNull DataOutput out, @NotNull final ValueContainer container) throws IOException { DataInputOutputUtil.writeSINT(out, container.size()); for (final Iterator valueIterator = container.getValueIterator(); valueIterator.hasNext();) { final T value = valueIterator.next(); myExternalizer.save(out, value); final ValueContainer.IntIterator ids = container.getInputIdsIterator(value); - if (ids != null) { - DataInputOutputUtil.writeSINT(out, ids.size()); - while (ids.hasNext()) { - final int id = ids.next(); - DataInputOutputUtil.writeSINT(out, id); - } - } - else { - DataInputOutputUtil.writeSINT(out, 0); + DataInputOutputUtil.writeSINT(out, ids.size()); + while (ids.hasNext()) { + final int id = ids.next(); + DataInputOutputUtil.writeSINT(out, id); } } } @NotNull @Override - public ValueContainerImpl read(final DataInput in) throws IOException { + public ValueContainerImpl read(@NotNull final DataInput in) throws IOException { DataInputStream stream = (DataInputStream)in; final ValueContainerImpl valueContainer = new ValueContainerImpl(); diff --git a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java index a42a1bfab18a..445ac0126047 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java @@ -240,7 +240,7 @@ public class GeneralCommandLine implements UserDataHolder { commands = CommandLineUtil.toCommandLine(myExePath, myProgramParams.getList()); } catch (ExecutionException e) { - LOG.warn(e); + LOG.info(e); throw e; } @@ -248,7 +248,7 @@ public class GeneralCommandLine implements UserDataHolder { return startProcess(commands); } catch (IOException e) { - LOG.warn(e); + LOG.info(e); throw new ProcessNotCreatedException(e.getMessage(), e, this); } } diff --git a/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.java b/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.java index 219f23bced4f..359924225981 100644 --- a/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.java +++ b/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -18,13 +18,15 @@ package com.intellij.ide.caches; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; public interface CacheUpdater { int getNumberOfPendingUpdateJobs(); - VirtualFile[] queryNeededFiles(ProgressIndicator indicator); + @NotNull + VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator); - void processFile(FileContent fileContent); + void processFile(@NotNull FileContent fileContent); void updatingDone(); diff --git a/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java b/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java index 55960fb8296e..9a0af4ad83a2 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -29,8 +30,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; -import java.nio.charset.Charset; import java.nio.ByteBuffer; +import java.nio.charset.Charset; /** * Allows to compare some text not associated with file or document. @@ -210,16 +211,18 @@ public class SimpleContent extends DiffContent { private static class LineSeparators { private String mySeparator; - public String correctText(String text) { - LineTokenizer lineTokenizer = new LineTokenizer(text); - String[] lines = lineTokenizer.execute(); + @NotNull + public String correctText(@NotNull String text) { + DiffString.LineTokenizer lineTokenizer = new DiffString.LineTokenizer(DiffString.create(text)); + DiffString[] lines = lineTokenizer.execute(); mySeparator = lineTokenizer.getLineSeparator(); LOG.assertTrue(mySeparator == null || !mySeparator.isEmpty()); if (mySeparator == null) mySeparator = SystemProperties.getLineSeparator(); - return LineTokenizer.concatLines(lines); + return DiffString.concatenate(lines).toString(); } - public String restoreText(String text) { + @NotNull + public String restoreText(@NotNull String text) { if (mySeparator == null) throw new NullPointerException(); return text.replaceAll("\n", mySeparator); } diff --git a/platform/platform-api/src/com/intellij/util/ui/Animator.java b/platform/platform-api/src/com/intellij/util/ui/Animator.java index a7d9301a791f..9b0256012fd3 100644 --- a/platform/platform-api/src/com/intellij/util/ui/Animator.java +++ b/platform/platform-api/src/com/intellij/util/ui/Animator.java @@ -131,7 +131,10 @@ public abstract class Animator implements Disposable { public void resume() { final Application app = ApplicationManager.getApplication(); - if (app == null || app.isUnitTestMode()) return; + if (app == null || app.isUnitTestMode()) { + animationDone(); + return; + } if (myCycleDuration == 0) { myCurrentFrame = myTotalFrames - 1; diff --git a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java index 6e6c052d0e3b..39886a2eb20a 100644 --- a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java +++ b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -33,6 +33,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.WindowManager; import com.intellij.ui.HyperlinkAdapter; import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.PropertyKey; @@ -119,6 +120,10 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter { } private static void startDiskSpaceMonitoring() { + if (SystemProperties.getBooleanProperty("idea.no.system.path.space.monitoring", false)) { + return; + } + final File file = new File(PathManager.getSystemPath()); final AtomicBoolean reported = new AtomicBoolean(); final ThreadLocal> ourFreeSpaceCalculation = new ThreadLocal>(); diff --git a/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java b/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java index 14e6d9265f07..855c898ae207 100644 --- a/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -27,6 +27,7 @@ import com.intellij.openapi.project.DumbServiceImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.TimeoutUtil; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -50,14 +51,15 @@ public class ToggleDumbModeAction extends AnAction implements DumbAware { return 0; } - public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { + @NotNull + public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) { while (myDumb) { TimeoutUtil.sleep(100); } return VirtualFile.EMPTY_ARRAY; } - public void processFile(FileContent fileContent) { + public void processFile(@NotNull FileContent fileContent) { } public void updatingDone() { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/DiffPanelComboBoxAction.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/DiffPanelComboBoxAction.java new file mode 100644 index 000000000000..b3ef9595782f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/DiffPanelComboBoxAction.java @@ -0,0 +1,94 @@ +package com.intellij.openapi.diff.actions; + +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.diff.DiffBundle; +import com.intellij.openapi.diff.ex.DiffPanelEx; +import com.intellij.openapi.diff.impl.DiffPanelImpl; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.Map; + +public abstract class DiffPanelComboBoxAction extends ComboBoxAction implements DumbAware { + @NotNull private final Map myActions = new HashMap(); + @NotNull private final T[] myActionOrder; + + protected DiffPanelComboBoxAction(@NotNull T[] actionOrder) { + myActionOrder = actionOrder; + } + + @NotNull + protected abstract String getActionName(); + + @NotNull + protected abstract T getCurrentOption(@NotNull DiffPanelEx diffPanel); + + @Nullable + private static DiffPanelEx getDiffPanel(@NotNull DataContext context) { + return DiffPanelImpl.fromDataContext(context); + } + + protected void addAction(T key, @NotNull AnAction action) { + myActions.put(key, action); + } + + @Override + public JComponent createCustomComponent(final Presentation presentation) { + JPanel panel = new JPanel(new BorderLayout()); + final JLabel label = new JLabel(getActionName()); + label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); + panel.add(label, BorderLayout.WEST); + panel.add(super.createCustomComponent(presentation), BorderLayout.CENTER); + return panel; + } + + @NotNull + @Override + protected DefaultActionGroup createPopupActionGroup(JComponent button) { + DefaultActionGroup actionGroup = new DefaultActionGroup(); + for (T option : myActionOrder) { + actionGroup.add(myActions.get(option)); + } + return actionGroup; + } + + @Override + public void update(AnActionEvent e) { + super.update(e); + Presentation presentation = e.getPresentation(); + DiffPanelEx diffPanel = getDiffPanel(e.getDataContext()); + if (diffPanel != null && diffPanel.getComponent().isDisplayable()) { + AnAction action = myActions.get(getCurrentOption(diffPanel)); + Presentation templatePresentation = action.getTemplatePresentation(); + presentation.setIcon(templatePresentation.getIcon()); + presentation.setText(templatePresentation.getText()); + presentation.setEnabled(true); + } + else { + presentation.setIcon(null); + presentation.setText(DiffBundle.message("diff.panel.combo.box.action.not.available.action.name")); + presentation.setEnabled(false); + } + } + + protected static abstract class DiffPanelAction extends DumbAwareAction { + public DiffPanelAction(@NotNull String text) { + super(text); + } + + public void actionPerformed(AnActionEvent e) { + final DiffPanelEx diffPanel = getDiffPanel(e.getDataContext()); + if (diffPanel != null) { + perform(diffPanel); + } + } + + protected abstract void perform(@NotNull DiffPanelEx diffPanel); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java index 8ae6fa277738..65f5eb346120 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java @@ -15,89 +15,48 @@ */ package com.intellij.openapi.diff.actions; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.diff.ex.DiffPanelEx; -import com.intellij.openapi.diff.impl.DiffPanelImpl; import com.intellij.openapi.diff.impl.processing.HighlightMode; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; -import java.util.Map; - -public class HighlightModeAction extends ComboBoxAction implements DumbAware { - private final Map myActions = new HashMap(); - private static final HighlightMode[] ourActionOrder = - new HighlightMode[]{HighlightMode.BY_WORD, HighlightMode.BY_LINE, HighlightMode.NO_HIGHLIGHTING}; +public class HighlightModeAction extends DiffPanelComboBoxAction { + private static final HighlightMode[] ourActionOrder = new HighlightMode[]{ + HighlightMode.BY_WORD, + HighlightMode.BY_LINE, + HighlightMode.NO_HIGHLIGHTING + }; public HighlightModeAction() { - myActions.put(HighlightMode.BY_WORD, - new SetHighlightModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.word"), HighlightMode.BY_WORD)); - myActions.put(HighlightMode.BY_LINE, - new SetHighlightModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.line"), HighlightMode.BY_LINE)); - myActions.put(HighlightMode.NO_HIGHLIGHTING, - new SetHighlightModeAction(DiffBundle.message("diff.acton.highlight.mode.action.no.highlighting"), - HighlightMode.NO_HIGHLIGHTING)); - } - - @Override - public JComponent createCustomComponent(final Presentation presentation) { - JPanel panel = new JPanel(new BorderLayout()); - final JLabel label = new JLabel(DiffBundle.message("diff.acton.highlight.mode.action.name")); - label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); - panel.add(label, BorderLayout.WEST); - panel.add(super.createCustomComponent(presentation), BorderLayout.CENTER); - return panel; + super(ourActionOrder); + addAction(HighlightMode.BY_WORD, new HighlightingModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.word"), HighlightMode.BY_WORD)); + addAction(HighlightMode.BY_LINE, new HighlightingModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.line"), HighlightMode.BY_LINE)); + addAction(HighlightMode.NO_HIGHLIGHTING, new HighlightingModeAction(DiffBundle.message("diff.acton.highlight.mode.action.no.highlighting"), HighlightMode.NO_HIGHLIGHTING)); } @NotNull - protected DefaultActionGroup createPopupActionGroup(JComponent button) { - DefaultActionGroup actionGroup = new DefaultActionGroup(); - for (HighlightMode comparisonPolicy : ourActionOrder) { - actionGroup.add(myActions.get(comparisonPolicy)); - } - return actionGroup; + @Override + protected String getActionName() { + return DiffBundle.message("diff.acton.highlight.mode.action.name"); } - public void update(AnActionEvent e) { - super.update(e); - Presentation presentation = e.getPresentation(); - DiffPanelEx diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null && diffPanel.getComponent().isDisplayable()) { - AnAction action = myActions.get(diffPanel.getHighlightMode()); - Presentation templatePresentation = action.getTemplatePresentation(); - presentation.setIcon(templatePresentation.getIcon()); - presentation.setText(templatePresentation.getText()); - presentation.setEnabled(true); - } - else { - presentation.setIcon(null); - presentation.setText(DiffBundle.message("diff.acton.highlight.mode.not.available.action.name")); - presentation.setEnabled(false); - } + @NotNull + @Override + protected HighlightMode getCurrentOption(@NotNull DiffPanelEx diffPanel) { + return diffPanel.getHighlightMode(); } - private static class SetHighlightModeAction extends DumbAwareAction { + private static class HighlightingModeAction extends DiffPanelAction { private final HighlightMode myHighlightMode; - public SetHighlightModeAction(String text, HighlightMode mode) { + public HighlightingModeAction(String text, HighlightMode highlightMode) { super(text); - myHighlightMode = mode; + myHighlightMode = highlightMode; } - public void actionPerformed(AnActionEvent e) { - final DiffPanelImpl diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null) { - diffPanel.setHighlightMode(myHighlightMode); - } + @Override + protected void perform(@NotNull DiffPanelEx diffPanel) { + diffPanel.setHighlightMode(myHighlightMode); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java index 930db0e4f337..a46d8b1516c7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java @@ -15,74 +15,38 @@ */ package com.intellij.openapi.diff.actions; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.diff.ex.DiffPanelEx; import com.intellij.openapi.diff.impl.ComparisonPolicy; -import com.intellij.openapi.diff.impl.DiffPanelImpl; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; -import java.util.Map; - -public class IgnoreWhiteSpacesAction extends ComboBoxAction implements DumbAware { - private final Map myActions = new HashMap(); +public class IgnoreWhiteSpacesAction extends DiffPanelComboBoxAction { private static final ComparisonPolicy[] ourActionOrder = new ComparisonPolicy[]{ ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_SPACE, - ComparisonPolicy.IGNORE_SPACE}; + ComparisonPolicy.IGNORE_SPACE + }; public IgnoreWhiteSpacesAction() { - myActions.put(ComparisonPolicy.DEFAULT, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.do.not.ignore"), ComparisonPolicy.DEFAULT)); - myActions.put(ComparisonPolicy.TRIM_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.leading.and.trailing"), ComparisonPolicy.TRIM_SPACE)); - myActions.put(ComparisonPolicy.IGNORE_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.all"), ComparisonPolicy.IGNORE_SPACE)); - } - - @Override - public JComponent createCustomComponent(final Presentation presentation) { - JPanel panel = new JPanel(new BorderLayout()); - final JLabel label = new JLabel(DiffBundle.message("ignore.whitespace.acton.name")); - label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); - panel.add(label, BorderLayout.WEST); - panel.add(super.createCustomComponent(presentation), BorderLayout.CENTER); - return panel; + super(ourActionOrder); + addAction(ComparisonPolicy.DEFAULT, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.do.not.ignore"), ComparisonPolicy.DEFAULT)); + addAction(ComparisonPolicy.TRIM_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.leading.and.trailing"), ComparisonPolicy.TRIM_SPACE)); + addAction(ComparisonPolicy.IGNORE_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.all"), ComparisonPolicy.IGNORE_SPACE)); } @NotNull - protected DefaultActionGroup createPopupActionGroup(JComponent button) { - DefaultActionGroup actionGroup = new DefaultActionGroup(); - for (ComparisonPolicy comparisonPolicy : ourActionOrder) { - actionGroup.add(myActions.get(comparisonPolicy)); - } - return actionGroup; + @Override + protected String getActionName() { + return DiffBundle.message("ignore.whitespace.acton.name"); } - public void update(AnActionEvent e) { - super.update(e); - Presentation presentation = e.getPresentation(); - DiffPanelEx diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null && diffPanel.getComponent().isDisplayable()) { - AnAction action = myActions.get(diffPanel.getComparisonPolicy()); - Presentation templatePresentation = action.getTemplatePresentation(); - presentation.setIcon(templatePresentation.getIcon()); - presentation.setText(templatePresentation.getText()); - presentation.setEnabled(true); - } else { - presentation.setIcon(null); - presentation.setText(DiffBundle.message("ignore.whitespace.action.not.available.action.name")); - presentation.setEnabled(false); - } + @NotNull + @Override + protected ComparisonPolicy getCurrentOption(@NotNull DiffPanelEx diffPanel) { + return diffPanel.getComparisonPolicy(); } - private static class IgnoringPolicyAction extends DumbAwareAction { + private static class IgnoringPolicyAction extends DiffPanelAction { private final ComparisonPolicy myPolicy; public IgnoringPolicyAction(String text, ComparisonPolicy policy) { @@ -90,11 +54,9 @@ public class IgnoreWhiteSpacesAction extends ComboBoxAction implements DumbAware myPolicy = policy; } - public void actionPerformed(AnActionEvent e) { - final DiffPanelImpl diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null) { - diffPanel.setComparisonPolicy(myPolicy); - } + @Override + protected void perform(@NotNull DiffPanelEx diffPanel) { + diffPanel.setComparisonPolicy(myPolicy); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java index a3715fdeaec4..1ee83be74224 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java @@ -19,11 +19,10 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.diff.DiffContent; import com.intellij.openapi.diff.DiffContentUtil; import com.intellij.openapi.diff.DiffViewer; -import com.intellij.openapi.diff.LineTokenizer; -import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.external.DiffManagerImpl; import com.intellij.openapi.diff.impl.fragments.Fragment; import com.intellij.openapi.diff.impl.fragments.LineFragment; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.impl.util.FocusDiffSide; import com.intellij.openapi.diff.impl.util.TextDiffType; import com.intellij.openapi.editor.Document; @@ -34,7 +33,6 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.FrameWrapper; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ImageLoader; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -47,7 +45,7 @@ public class DiffUtil { private DiffUtil() { } - public static void initDiffFrame(Project project, FrameWrapper frameWrapper, final DiffViewer diffPanel, final JComponent mainComponent) { + public static void initDiffFrame(Project project, @NotNull FrameWrapper frameWrapper, @NotNull final DiffViewer diffPanel, final JComponent mainComponent) { frameWrapper.setComponent(mainComponent); frameWrapper.setProject(project); frameWrapper.setImage(ImageLoader.loadFromResource("/diff/Diff.png")); @@ -56,15 +54,17 @@ public class DiffUtil { } @Nullable - public static FocusDiffSide getFocusDiffSide(DataContext dataContext) { + public static FocusDiffSide getFocusDiffSide(@NotNull DataContext dataContext) { return FocusDiffSide.DATA_KEY.getData(dataContext); } - public static String[] convertToLines(@NotNull String text) { - return new LineTokenizer(text).execute(); + @NotNull + public static DiffString[] convertToLines(@NotNull String text) { + return DiffString.create(text).tokenize(); } - public static FileType[] chooseContentTypes(DiffContent[] contents) { + @NotNull + public static FileType[] chooseContentTypes(@NotNull DiffContent[] contents) { FileType commonType = FileTypes.PLAIN_TEXT; for (DiffContent content : contents) { FileType contentType = content.getContentType(); @@ -78,7 +78,7 @@ public class DiffUtil { return result; } - public static boolean isWritable(DiffContent content) { + public static boolean isWritable(@NotNull DiffContent content) { Document document = content.getDocument(); return document != null && document.isWritable(); } @@ -92,7 +92,7 @@ public class DiffUtil { return editor; } - public static void drawBoldDottedFramingLines(Graphics2D g, int startX, int endX, int startY, int bottomY, Color color) { + public static void drawBoldDottedFramingLines(@NotNull Graphics2D g, int startX, int endX, int startY, int bottomY, @NotNull Color color) { UIUtil.drawBoldDottedLine(g, startX, endX, startY, null, color, false); UIUtil.drawBoldDottedLine(g, startX, endX, bottomY, null, color, false); } @@ -102,8 +102,9 @@ public class DiffUtil { UIUtil.drawLine(g, startX, y + 1, endX, y + 1, null, color); } - public static Color getFramingColor(@NotNull Color backgroundColor) { - return backgroundColor.darker(); + @Nullable + public static Color getFramingColor(@Nullable Color backgroundColor) { + return backgroundColor != null ? backgroundColor.darker() : null; } @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java index d3b273fdaba9..7e395c1b4a9e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java @@ -137,7 +137,8 @@ public class FragmentedDiffPanelState extends DiffPanelState { //setDiffPolicy(diffPolicy); diffPolicy.setRanges(ranges); - return addMarkup(new TextCompareProcessor(myComparisonPolicy, diffPolicy).process(myAppender1.getText(), myAppender2.getText())); + return addMarkup( + new TextCompareProcessor(myComparisonPolicy, diffPolicy, myHighlightMode).process(myAppender1.getText(), myAppender2.getText())); } private BeforeAfter lineStarts(int i) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java index db11ed063c7e..3fd7df130e45 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java @@ -15,11 +15,14 @@ */ package com.intellij.openapi.diff.impl.highlighting; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.processing.DiffPolicy; import com.intellij.openapi.util.TextRange; import com.intellij.util.BeforeAfter; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; import java.util.ArrayList; import java.util.Arrays; @@ -33,19 +36,28 @@ import java.util.List; public class PresetBlocksDiffPolicy implements DiffPolicy { // fragment _start_ offsets private List> myRanges; - private final DiffPolicy myDelegate; + @NotNull private final DiffPolicy myDelegate; - public PresetBlocksDiffPolicy(DiffPolicy delegate) { + public PresetBlocksDiffPolicy(@NotNull DiffPolicy delegate) { myDelegate = delegate; } + @TestOnly + @NotNull @Override - public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { + public DiffFragment[] buildFragments(@NotNull String text1, @NotNull String text2) throws FilesTooBigForDiffException { + return buildFragments(DiffString.create(text1), DiffString.create(text2)); + } + + @NotNull + @Override + public DiffFragment[] buildFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { final List fragments = new ArrayList(); for (int i = 0; i < myRanges.size(); i++) { final BeforeAfter range = myRanges.get(i); - fragments.addAll(Arrays.asList(myDelegate.buildFragments(new String(text1.substring(range.getBefore().getStartOffset(), range.getBefore().getEndOffset())), - new String(text2.substring(range.getAfter().getStartOffset(), range.getAfter().getEndOffset()))))); + fragments.addAll(Arrays.asList(myDelegate.buildFragments( + text1.substring(range.getBefore().getStartOffset(), range.getBefore().getEndOffset()).copy(), + text2.substring(range.getAfter().getStartOffset(), range.getAfter().getEndOffset()).copy()))); } return fragments.toArray(new DiffFragment[fragments.size()]); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java index 14c235470347..d3e1dfd5a64a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java @@ -30,8 +30,8 @@ import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; +import java.util.List; public abstract class SimpleDiffPanelState implements Disposable { protected ComparisonPolicy myComparisonPolicy = ComparisonPolicy.DEFAULT; @@ -84,7 +84,7 @@ public abstract class SimpleDiffPanelState implements Disposable { public void dispose() { } - private LineBlocks addMarkup(final ArrayList lines) { + private LineBlocks addMarkup(final List lines) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { final FragmentHighlighterImpl fragmentHighlighter = new FragmentHighlighterImpl(myAppender1, myAppender2); @@ -114,12 +114,8 @@ public abstract class SimpleDiffPanelState implements Disposable { return LineBlocks.EMPTY; } - if (myHighlightMode == HighlightMode.NO_HIGHLIGHTING) { - return LineBlocks.fromLineFragments(Collections.emptyList()); - } - - return addMarkup(new TextCompareProcessor(myComparisonPolicy, myDiffPolicy, myHighlightMode == HighlightMode.BY_WORD) - .process(myAppender1.getText(), myAppender2.getText())); + return addMarkup( + new TextCompareProcessor(myComparisonPolicy, myDiffPolicy, myHighlightMode).process(myAppender1.getText(), myAppender2.getText())); } public Project getProject() { return myProject; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java index dc0e98e722fb..bbd8c929c203 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl.incrementalMerge; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.DiffUtil; @@ -29,6 +30,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -108,12 +110,12 @@ public class ChangeList { private ArrayList buildChanges() throws FilesTooBigForDiffException { Document base = getDocument(FragmentSide.SIDE1); - String[] baseLines = DiffUtil.convertToLines(base.getText()); + DiffString[] baseLines = DiffUtil.convertToLines(base.getText()); Document version = getDocument(FragmentSide.SIDE2); - String[] versionLines = DiffUtil.convertToLines(version.getText()); + DiffString[] versionLines = DiffUtil.convertToLines(version.getText()); DiffFragment[] fragments = ComparisonPolicy.DEFAULT.buildDiffFragmentsFromLines(baseLines, versionLines); final ArrayList result = new ArrayList(); - new DiffFragmemntsEnumerator(fragments) { + new DiffFragmentsEnumerator(fragments) { protected void process(DiffFragment fragment) { if (fragment.isEqual()) return; Context context = getContext(); @@ -129,11 +131,11 @@ public class ChangeList { return myChanges.get(index); } - private abstract static class DiffFragmemntsEnumerator { + private abstract static class DiffFragmentsEnumerator { private final DiffFragment[] myFragments; private final Context myContext; - private DiffFragmemntsEnumerator(DiffFragment[] fragments) { + private DiffFragmentsEnumerator(DiffFragment[] fragments) { myContext = new Context(); myFragments = fragments; } @@ -142,8 +144,8 @@ public class ChangeList { for (DiffFragment fragment : myFragments) { myContext.myFragment = fragment; process(fragment); - String text1 = fragment.getText1(); - String text2 = fragment.getText2(); + DiffString text1 = fragment.getText1(); + DiffString text2 = fragment.getText2(); myContext.myStarts[0] += StringUtil.length(text1); myContext.myStarts[1] += StringUtil.length(text2); myContext.myLines[0] += countLines(text1); @@ -151,7 +153,7 @@ public class ChangeList { } } - private static int countLines(String text) { + private static int countLines(@Nullable DiffString text) { if (text == null) return 0; return StringUtil.countNewLines(text); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java index 2c1b1e267b15..d3a0b5a50d58 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java @@ -24,6 +24,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.diff.DiffContent; import com.intellij.openapi.diff.DiffRequest; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.incrementalMerge.ui.MergePanel2; @@ -149,8 +150,8 @@ public class MergeList implements UserDataHolder { @NotNull String baseText, @NotNull String rightText, @NotNull ContextLogger logger) throws FilesTooBigForDiffException { - DiffFragment[] leftFragments = DiffPolicy.DEFAULT_LINES.buildFragments(baseText, leftText); - DiffFragment[] rightFragments = DiffPolicy.DEFAULT_LINES.buildFragments(baseText, rightText); + DiffFragment[] leftFragments = DiffPolicy.DEFAULT_LINES.buildFragments(DiffString.create(baseText), DiffString.create(leftText)); + DiffFragment[] rightFragments = DiffPolicy.DEFAULT_LINES.buildFragments(DiffString.create(baseText), DiffString.create(rightText)); int[] leftOffsets = {0, 0}; int[] rightOffsets = {0, 0}; int leftIndex = 0; @@ -188,7 +189,7 @@ public class MergeList implements UserDataHolder { leftOffsets[1] += versionLength; } - private static int getTextLength(@Nullable String text1) { + private static int getTextLength(@Nullable DiffString text1) { return text1 != null ? text1.length() : 0; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java index 2a6a01c10414..2d41620f6de2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java @@ -18,35 +18,47 @@ package com.intellij.openapi.diff.impl.processing; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.text.StringUtil; class PreferWholeLines implements DiffCorrection { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.PreferWholeLines"); public static final DiffCorrection INSTANCE = new PreferWholeLines(); + public DiffFragment[] correct(DiffFragment[] fragments) { for (int i = 1; i < fragments.length - 1; i++) { DiffFragment fragment = fragments[i]; if (!fragment.isOneSide()) continue; DiffFragment nextFragment = fragments[i + 1]; FragmentSide side = FragmentSide.chooseSide(fragment); + + DiffString fragmentText = side.getText(fragment); + DiffString otherNextFragmentText = side.getOtherText(nextFragment); + DiffString nextFragmentText = side.getText(nextFragment); + if (nextFragment.isOneSide()) { - LOG.error("<" + side.getText(fragment) + "> <" + side.getOtherText(nextFragment) + ">"); + LOG.error("<" + fragmentText + "> <" + otherNextFragmentText + ">"); } - if (StringUtil.startsWithChar(side.getText(fragment), '\n') && - StringUtil.startsWithChar(side.getText(nextFragment), '\n') && - StringUtil.startsWithChar(side.getOtherText(nextFragment), '\n')) { + if (StringUtil.startsWithChar(fragmentText, '\n') && + StringUtil.startsWithChar(nextFragmentText, '\n') && + StringUtil.startsWithChar(otherNextFragmentText, '\n')) { + DiffFragment previous = fragments[i - 1]; - previous = side.createFragment(side.getText(previous) + "\n", - side.getOtherText(previous) + "\n", - previous.isModified()); + DiffString previousText = side.getText(previous); + DiffString otherPreciousText = side.getOtherText(previous); + + assert previous != null; + assert previousText != null; + assert otherPreciousText != null; + assert fragmentText != null; + assert nextFragmentText != null; + assert otherNextFragmentText != null; + + previous = side.createFragment(previousText.append('\n'), otherPreciousText.append('\n'), previous.isModified()); fragments[i - 1] = previous; - fragment = side.createFragment(side.getText(fragment).substring(1) + "\n", - side.getOtherText(fragment), - fragment.isModified()); + fragment = side.createFragment(fragmentText.substring(1).append('\n'), side.getOtherText(fragment), fragment.isModified()); fragments[i] = fragment; - nextFragment = side.createFragment(side.getText(nextFragment).substring(1), - side.getOtherText(nextFragment).substring(1), - nextFragment.isModified()); + nextFragment = side.createFragment(nextFragmentText.substring(1), otherNextFragmentText.substring(1), nextFragment.isModified()); fragments[i + 1] = nextFragment; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java index e527964a5c0d..1ae503e06d64 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java @@ -23,53 +23,59 @@ import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.LineBlockDivider; import com.intellij.openapi.diff.impl.highlighting.Util; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class TextCompareProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.Processor"); - private final DiffPolicy myDiffPolicy; @NotNull private final ComparisonPolicy myComparisonPolicy; - private final boolean mySearchForSubFragments; + @NotNull private final DiffPolicy myDiffPolicy; + @NotNull private final HighlightMode myHighlightMode; public TextCompareProcessor(@NotNull ComparisonPolicy comparisonPolicy, - final DiffPolicy diffPolicy, - boolean searchForSubFragments) { + @NotNull DiffPolicy diffPolicy, + @NotNull HighlightMode highlightMode) { myComparisonPolicy = comparisonPolicy; myDiffPolicy = diffPolicy; - mySearchForSubFragments = searchForSubFragments; - } - - public TextCompareProcessor(@NotNull ComparisonPolicy comparisonPolicy, final DiffPolicy diffPolicy) { - this(comparisonPolicy, diffPolicy, true); + myHighlightMode = highlightMode; } public TextCompareProcessor(@NotNull ComparisonPolicy comparisonPolicy) { - this(comparisonPolicy, DiffPolicy.LINES_WO_FORMATTING); + this(comparisonPolicy, DiffPolicy.LINES_WO_FORMATTING, HighlightMode.BY_WORD); } - public ArrayList process(@Nullable String text1, @Nullable String text2) throws FilesTooBigForDiffException { + public List process(@Nullable String text1, @Nullable String text2) throws FilesTooBigForDiffException { + if (myHighlightMode == HighlightMode.NO_HIGHLIGHTING) { + return Collections.emptyList(); + } + text1 = StringUtil.notNullize(text1); text2 = StringUtil.notNullize(text2); if (text1.isEmpty() || text2.isEmpty()) { return new DummyDiffFragmentsProcessor().process(text1, text2); } - DiffFragment[] woFormattingBlocks = myDiffPolicy.buildFragments(text1, text2); + DiffString diffText1 = DiffString.create(text1); + DiffString diffText2 = DiffString.create(text2); + + DiffFragment[] woFormattingBlocks = myDiffPolicy.buildFragments(diffText1, diffText2); DiffFragment[] step1lineFragments = new DiffCorrection.TrueLineBlocks(myComparisonPolicy).correctAndNormalize(woFormattingBlocks); ArrayList lineBlocks = new DiffFragmentsProcessor().process(step1lineFragments); int badLinesCount = 0; - if (mySearchForSubFragments) { + if (myHighlightMode == HighlightMode.BY_WORD) { for (LineFragment lineBlock : lineBlocks) { if (lineBlock.isOneSide() || lineBlock.isEqual()) continue; try { - String subText1 = lineBlock.getText(text1, FragmentSide.SIDE1); - String subText2 = lineBlock.getText(text2, FragmentSide.SIDE2); + DiffString subText1 = lineBlock.getText(diffText1, FragmentSide.SIDE1); + DiffString subText2 = lineBlock.getText(diffText2, FragmentSide.SIDE2); ArrayList subFragments = findSubFragments(subText1, subText2); lineBlock.setChildren(new ArrayList(subFragments)); lineBlock.adjustTypeFromChildrenTypes(); @@ -84,7 +90,7 @@ public class TextCompareProcessor { return lineBlocks; } - private ArrayList findSubFragments(String text1, String text2) throws FilesTooBigForDiffException { + private ArrayList findSubFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { DiffFragment[] fragments = new ByWord(myComparisonPolicy).buildFragments(text1, text2); fragments = DiffCorrection.ConnectSingleSideToChange.INSTANCE.correct(fragments); fragments = UniteSameType.INSTANCE.correct(fragments); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java index 33db73f3a8eb..6e6a60702595 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java @@ -23,6 +23,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.util.Comparing; import com.intellij.util.ui.GraphicsUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.*; import java.awt.geom.CubicCurve2D; @@ -34,7 +36,7 @@ import java.util.ArrayList; */ public class DividerPolygon { - private final Color myColor; + @Nullable private final Color myColor; private final int myStart1; private final int myStart2; private final int myEnd1; @@ -43,7 +45,7 @@ public class DividerPolygon { public static final double CTRL_PROXIMITY_X = 0.3; - public DividerPolygon(int start1, int start2, int end1, int end2, Color color, boolean applied) { + public DividerPolygon(int start1, int start2, int end1, int end2, @Nullable Color color, boolean applied) { myApplied = applied; myStart1 = advance(start1); myStart2 = advance(start2); @@ -150,7 +152,9 @@ public class DividerPolygon { //g.setComposite(composite); } - public static ArrayList createVisiblePolygons(EditingSides sides, FragmentSide left, int diffDividerPolygonsOffset) { + public static ArrayList createVisiblePolygons(@NotNull EditingSides sides, + @NotNull FragmentSide left, + int diffDividerPolygonsOffset) { Editor editor1 = sides.getEditor(left); Editor editor2 = sides.getEditor(left.otherSide()); LineBlocks lineBlocks = sides.getLineBlocks(); @@ -174,7 +178,10 @@ public class DividerPolygon { return new FoldingTransformation(editor); } - private static DividerPolygon createPolygon(Transformation[] transformations, Trapezium trapezium, Color color, FragmentSide left, + private static DividerPolygon createPolygon(@NotNull Transformation[] transformations, + @NotNull Trapezium trapezium, + @Nullable Color color, + @NotNull FragmentSide left, int diffDividerPolygonsOffset, boolean applied) { Interval base1 = trapezium.getBase(left); Interval base2 = trapezium.getBase(left.otherSide()); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java index 5cfc4d00facb..1bbf9aae650c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java @@ -201,7 +201,7 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList } private void runBatchFoldingOperation(final Runnable operation, final boolean dontCollapseCaret, final boolean moveCaret) { - assert SwingUtilities.isEventDispatchThread() : Thread.currentThread(); + LOG.assertTrue(SwingUtilities.isEventDispatchThread(), Thread.currentThread().toString()); assertIsDispatchThreadForEditor(); boolean oldDontCollapseCaret = myDoNotCollapseCaret; myDoNotCollapseCaret |= dontCollapseCaret; diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java index 4a3c268d25e2..d54bfcc304b4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java @@ -251,6 +251,7 @@ public class PluginsAdvertiser implements StartupActivity { if (project.isDisposed()) return; if (extensions == null) { loadSupportedExtensions(myAllPlugins); + if (project.isDisposed()) return; EditorNotifications.getInstance(project).updateAllNotifications(); } final Map ids = new HashMap(); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java index 7f0b5e8a4e9d..e12d756d901e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -260,14 +260,14 @@ public class JarHandler extends JarHandlerBase { private final byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, CacheLibraryInfo value) throws IOException { + public void save(@NotNull DataOutput out, CacheLibraryInfo value) throws IOException { IOUtil.writeUTFFast(myBuffer, out, value.mySnapshotPath); out.writeLong(value.myModificationTime); out.writeLong(value.myFileLength); } @Override - public CacheLibraryInfo read(DataInput in) throws IOException { + public CacheLibraryInfo read(@NotNull DataInput in) throws IOException { return new CacheLibraryInfo(IOUtil.readUTFFast(myBuffer, in), in.readLong(), in.readLong()); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index c1c7cd6371fb..de9a6d51b498 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -543,12 +543,12 @@ public class FSRecords implements Forceable { private static class ContentHashesDescriptor implements KeyDescriptor, DifferentSerializableBytesImplyNonEqualityPolicy { @Override - public void save(DataOutput out, byte[] value) throws IOException { + public void save(@NotNull DataOutput out, byte[] value) throws IOException { out.write(value); } @Override - public byte[] read(DataInput in) throws IOException { + public byte[] read(@NotNull DataInput in) throws IOException { byte[] b = new byte[SIGNATURE_LENGTH]; in.readFully(b); return b; diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.java index d0e7e97902f2..8908c3451a72 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.java @@ -18,6 +18,7 @@ package com.intellij.remotesdk; import com.intellij.openapi.util.PasswordUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.xmlb.annotations.Transient; +import org.jdom.Element; import org.jetbrains.annotations.Nullable; /** @@ -204,7 +205,7 @@ public class RemoteCredentialsHolder implements MutableRemoteCredentials { } } - public void copyTo(RemoteSdkCredentials to) { + public void copyRemoteCredentialsTo(RemoteSdkCredentials to) { to.setHost(getHost()); to.setPort(getPort()); to.setAnonymous(isAnonymous()); @@ -216,4 +217,41 @@ public class RemoteCredentialsHolder implements MutableRemoteCredentials { to.setStorePassword(isStorePassword()); to.setStorePassphrase(isStorePassphrase()); } + + public void load(Element element) { + setHost(element.getAttributeValue(HOST)); + setPort(StringUtil.parseInt(element.getAttributeValue(PORT), 22)); + setAnonymous(StringUtil.parseBoolean(element.getAttributeValue(ANONYMOUS), false)); + setSerializedUserName(element.getAttributeValue(USERNAME)); + setSerializedPassword(element.getAttributeValue(PASSWORD)); + setPrivateKeyFile(StringUtil.nullize(element.getAttributeValue(PRIVATE_KEY_FILE))); + setKnownHostsFile(StringUtil.nullize(element.getAttributeValue(KNOWN_HOSTS_FILE))); + setSerializedPassphrase(element.getAttributeValue(PASSPHRASE)); + setUseKeyPair(StringUtil.parseBoolean(element.getAttributeValue(USE_KEY_PAIR), false)); + } + + public void save(Element rootElement) { + rootElement.setAttribute(HOST, StringUtil.notNullize(getHost())); + rootElement.setAttribute(PORT, Integer.toString(getPort())); + rootElement.setAttribute(ANONYMOUS, Boolean.toString(isAnonymous())); + rootElement.setAttribute(USERNAME, getSerializedUserName()); + rootElement.setAttribute(PASSWORD, getSerializedPassword()); + rootElement.setAttribute(PRIVATE_KEY_FILE, StringUtil.notNullize(getPrivateKeyFile())); + rootElement.setAttribute(KNOWN_HOSTS_FILE, StringUtil.notNullize(getKnownHostsFile())); + rootElement.setAttribute(PASSPHRASE, getSerializedPassphrase()); + rootElement.setAttribute(USE_KEY_PAIR, Boolean.toString(isUseKeyPair())); + } + + public void copyFrom(RemoteCredentials from) { + setHost(from.getHost()); + setPort(from.getPort()); + setAnonymous(from.isAnonymous()); + setUserName(from.getUserName()); + setPassword(from.getPassword()); + setUseKeyPair(from.isUseKeyPair()); + setPrivateKeyFile(from.getPrivateKeyFile()); + setKnownHostsFile(from.getKnownHostsFile()); + setStorePassword(from.isStorePassword()); + setStorePassphrase(from.isStorePassphrase()); + } } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentials.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentials.java index 11f14f05119d..8d094aea8c46 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentials.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentials.java @@ -4,4 +4,5 @@ package com.intellij.remotesdk; * @author traff */ public interface RemoteSdkCredentials extends MutableRemoteCredentials, RemoteSdkProperties { + String getFullInterpreterPath(); } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsHolder.java index 88663598f9c6..6a2e5c2a485b 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsHolder.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsHolder.java @@ -1,11 +1,10 @@ package com.intellij.remotesdk; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.remotesdk2.RemoteConnectionCredentialsWrapper; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.LinkedList; import java.util.List; /** @@ -13,11 +12,6 @@ import java.util.List; */ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implements RemoteSdkCredentials { public static final String SSH_PREFIX = "ssh://"; - private static final String INTERPRETER_PATH = "INTERPRETER_PATH"; - private static final String HELPERS_PATH = "HELPERS_PATH"; - private static final String REMOTE_ROOTS = "REMOTE_ROOTS"; - private static final String REMOTE_PATH = "REMOTE_PATH"; - private static final String INITIALIZED = "INITIALIZED"; @NotNull private final RemoteSdkPropertiesHolder myRemoteSdkProperties; @@ -30,7 +24,6 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen return SSH_PREFIX + cred.getUserName() + "@" + cred.getHost() + ":" + cred.getPort() + cred.getInterpreterPath(); } - /** * Extracts interpreter path from full path generated by method getFullInterpreterPath * Returns fullPath as fallback @@ -118,7 +111,7 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen @Override public String getFullInterpreterPath() { - return myRemoteSdkProperties.getFullInterpreterPath(); + return constructSshCredentialsSdkFullPath(this); } @Override @@ -126,6 +119,11 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen myRemoteSdkProperties.setSdkId(sdkId); } + @Override + public String getSdkId() { + return myRemoteSdkProperties.getSdkId(); + } + @Override public boolean isInitialized() { return myRemoteSdkProperties.isInitialized(); @@ -138,64 +136,27 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen public static boolean isRemoteSdk(@Nullable String path) { if (path != null) { - return path.startsWith(SSH_PREFIX); + return path.startsWith(SSH_PREFIX) || path.startsWith(RemoteConnectionCredentialsWrapper.VAGRANT_PREFIX) || + path.startsWith(RemoteConnectionCredentialsWrapper.SFTP_DEPLOYMENT_PREFIX); } else { return false; } } - public void loadRemoteSdkCredentials(Element element) { - setHost(element.getAttributeValue(HOST)); - setPort(StringUtil.parseInt(element.getAttributeValue(PORT), 22)); - setAnonymous(StringUtil.parseBoolean(element.getAttributeValue(ANONYMOUS), false)); - setSerializedUserName(element.getAttributeValue(USERNAME)); - setSerializedPassword(element.getAttributeValue(PASSWORD)); - setPrivateKeyFile(StringUtil.nullize(element.getAttributeValue(PRIVATE_KEY_FILE))); - setKnownHostsFile(StringUtil.nullize(element.getAttributeValue(KNOWN_HOSTS_FILE))); - setSerializedPassphrase(element.getAttributeValue(PASSPHRASE)); - setUseKeyPair(StringUtil.parseBoolean(element.getAttributeValue(USE_KEY_PAIR), false)); - setInterpreterPath(StringUtil.nullize(element.getAttributeValue(INTERPRETER_PATH))); - setHelpersPath(StringUtil.nullize(element.getAttributeValue(HELPERS_PATH))); + @Override + public void load(Element element) { + super.load(element); - setRemoteRoots(loadStringsList(element, REMOTE_ROOTS, REMOTE_PATH)); - - setInitialized(StringUtil.parseBoolean(element.getAttributeValue(INITIALIZED), true)); + myRemoteSdkProperties.load(element); } - protected static List loadStringsList(Element element, String rootName, String attrName) { - final List paths = new LinkedList(); - if (element != null) { - @NotNull final List list = element.getChildren(rootName); - for (Object o : list) { - paths.add(((Element)o).getAttribute(attrName).getValue()); - } - } - return paths; - } + @Override + public void save(Element rootElement) { + super.save(rootElement); - public void saveRemoteSdkData(Element rootElement) { - rootElement.setAttribute(HOST, StringUtil.notNullize(getHost())); - rootElement.setAttribute(PORT, Integer.toString(getPort())); - rootElement.setAttribute(ANONYMOUS, Boolean.toString(isAnonymous())); - rootElement.setAttribute(USERNAME, getSerializedUserName()); - rootElement.setAttribute(PASSWORD, getSerializedPassword()); - rootElement.setAttribute(PRIVATE_KEY_FILE, StringUtil.notNullize(getPrivateKeyFile())); - rootElement.setAttribute(KNOWN_HOSTS_FILE, StringUtil.notNullize(getKnownHostsFile())); - rootElement.setAttribute(PASSPHRASE, getSerializedPassphrase()); - rootElement.setAttribute(USE_KEY_PAIR, Boolean.toString(isUseKeyPair())); - - rootElement.setAttribute(INTERPRETER_PATH, StringUtil.notNullize(getInterpreterPath())); - rootElement.setAttribute(HELPERS_PATH, StringUtil.notNullize(getHelpersPath())); - - rootElement.setAttribute(INITIALIZED, Boolean.toString(isInitialized())); - - for (String remoteRoot : getRemoteRoots()) { - final Element child = new Element(REMOTE_ROOTS); - child.setAttribute(REMOTE_PATH, remoteRoot); - rootElement.addContent(child); - } + myRemoteSdkProperties.save(rootElement); } @@ -268,8 +229,8 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen '}'; } - public void copyTo(RemoteSdkCredentialsHolder to) { - super.copyTo(to); + public void copyRemoteSdkCredentialsTo(RemoteSdkCredentialsHolder to) { + super.copyRemoteCredentialsTo(to); myRemoteSdkProperties.copyTo(to.getRemoteSdkProperties()); } } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkProperties.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkProperties.java index 5e98352accf6..ed7fe6bd00c0 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkProperties.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkProperties.java @@ -43,10 +43,10 @@ public interface RemoteSdkProperties { void setHelpersVersionChecked(boolean helpersVersionChecked); - String getFullInterpreterPath(); - void setSdkId(String sdkId); + String getSdkId(); + @Deprecated boolean isInitialized(); diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkPropertiesHolder.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkPropertiesHolder.java index 11f350ca10c5..5b63720a5d50 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkPropertiesHolder.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkPropertiesHolder.java @@ -15,6 +15,10 @@ */ package com.intellij.remotesdk; +import com.intellij.openapi.util.JDOMExternalizer; +import com.intellij.openapi.util.text.StringUtil; +import org.jdom.Element; + import java.util.ArrayList; import java.util.List; @@ -22,6 +26,12 @@ import java.util.List; * @author traff */ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { + private static final String INTERPRETER_PATH = "INTERPRETER_PATH"; + private static final String HELPERS_PATH = "HELPERS_PATH"; + private static final String REMOTE_ROOTS = "REMOTE_ROOTS"; + private static final String REMOTE_PATH = "REMOTE_PATH"; + private static final String INITIALIZED = "INITIALIZED"; + private String mySdkId; private String myInterpreterPath; @@ -93,15 +103,14 @@ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { myHelpersVersionChecked = helpersVersionChecked; } - @Override - public String getFullInterpreterPath() { - return mySdkId; - } - public void setSdkId(String sdkId) { mySdkId = sdkId; } + public String getSdkId() { + return mySdkId; + } + @Override public boolean isInitialized() { return myInitialized; @@ -113,7 +122,7 @@ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { } - public void copyTo(RemoteSdkPropertiesHolder copy) { + public void copyTo(RemoteSdkProperties copy) { copy.setInterpreterPath(getInterpreterPath()); copy.setHelpersPath(getHelpersPath()); copy.setHelpersVersionChecked(isHelpersVersionChecked()); @@ -122,4 +131,26 @@ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { copy.setInitialized(isInitialized()); } + + public void save(Element rootElement) { + rootElement.setAttribute(INTERPRETER_PATH, StringUtil.notNullize(getInterpreterPath())); + rootElement.setAttribute(HELPERS_PATH, StringUtil.notNullize(getHelpersPath())); + + rootElement.setAttribute(INITIALIZED, Boolean.toString(isInitialized())); + + for (String remoteRoot : getRemoteRoots()) { + final Element child = new Element(REMOTE_ROOTS); + child.setAttribute(REMOTE_PATH, remoteRoot); + rootElement.addContent(child); + } + } + + public void load(Element element) { + setInterpreterPath(StringUtil.nullize(element.getAttributeValue(INTERPRETER_PATH))); + setHelpersPath(StringUtil.nullize(element.getAttributeValue(HELPERS_PATH))); + + setRemoteRoots(JDOMExternalizer.loadStringsList(element, REMOTE_ROOTS, REMOTE_PATH)); + + setInitialized(StringUtil.parseBoolean(element.getAttributeValue(INITIALIZED), true)); + } } diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteConnectionCredentialsWrapper.java b/platform/platform-impl/src/com/intellij/remotesdk2/RemoteConnectionCredentialsWrapper.java new file mode 100644 index 000000000000..b51c9fb10b8f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remotesdk2/RemoteConnectionCredentialsWrapper.java @@ -0,0 +1,173 @@ +/* + * Copyright 2000-2014 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.remotesdk2; + +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.remotesdk.RemoteCredentials; +import com.intellij.remotesdk.RemoteCredentialsHolder; +import com.intellij.remotesdk.RemoteSdkCredentialsHolder; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; + +/** + * @author traff + */ +public class RemoteConnectionCredentialsWrapper { + public static final String VAGRANT_PREFIX = "vagrant://"; + public static final String SFTP_DEPLOYMENT_PREFIX = "sftp://"; + + public final Key VAGRANT_BASED_CREDENTIALS = Key.create("VAGRANT_BASED_CREDENTIALS"); + public final Key WEB_DEPLOYMENT_BASED_CREDENTIALS = Key.create("WEB_DEPLOYMENT_BASED_CREDENTIALS"); + + public final Key PLAIN_SSH_CREDENTIALS = Key.create("PLAIN_SSH_CREDENTIALS"); + + private UserDataHolderBase myCredentialsTypeHolder = new UserDataHolderBase(); + + public void setVagrantConnectionType(VagrantBasedCredentialsHolder vagrantBasedCredentials) { + myCredentialsTypeHolder.putUserData(VAGRANT_BASED_CREDENTIALS, vagrantBasedCredentials); + } + + + private VagrantBasedCredentialsHolder getVagrantCredentials() { + return myCredentialsTypeHolder.getUserData(VAGRANT_BASED_CREDENTIALS); + } + + public void setPlainSshCredentials(RemoteCredentialsHolder credentials) { + myCredentialsTypeHolder.putUserData(PLAIN_SSH_CREDENTIALS, credentials); + } + + private RemoteCredentialsHolder getPlainSshCredentials() { + return myCredentialsTypeHolder.getUserData(PLAIN_SSH_CREDENTIALS); + } + + + public void setWebDeploymentCredentials(WebDeploymentCredentialsHolder webDeploymentCredentials) { + myCredentialsTypeHolder.putUserData(WEB_DEPLOYMENT_BASED_CREDENTIALS, webDeploymentCredentials); + } + + private WebDeploymentCredentialsHolder getWebDeploymentCredentials() { + return myCredentialsTypeHolder.getUserData(WEB_DEPLOYMENT_BASED_CREDENTIALS); + } + + private boolean isVagrantConnection() { + return getVagrantCredentials() != null; + } + + private boolean isPlainSshConnection() { + return getPlainSshCredentials() != null; + } + + private boolean isWebDeploymentConnection() { + return getWebDeploymentCredentials() != null; + } + + + public Object getConnectionKey() { + if (isVagrantConnection()) { + return getVagrantCredentials(); + } + else if (isPlainSshConnection()) { + return getPlainSshCredentials(); + } + else if (isWebDeploymentConnection()) { + return getWebDeploymentCredentials(); + } + else { + throw unknownConnectionType(); + } + } + + public void save(final Element rootElement) { + switchType(new RemoteSdkConnectionAcceptor() { + @Override + public void ssh(RemoteCredentialsHolder cred) { + cred.save(rootElement); + } + + @Override + public void vagrant(VagrantBasedCredentialsHolder cred) { + cred.save(rootElement); + } + + @Override + public void deployment(WebDeploymentCredentialsHolder cred) { + cred.save(rootElement); + } + }); + } + + public static IllegalStateException unknownConnectionType() { + return new IllegalStateException("Unknown connection type"); //TODO + } + + public void copyTo(RemoteConnectionCredentialsWrapper copy) { + copy.myCredentialsTypeHolder = new UserDataHolderBase(); + copy.setPlainSshCredentials(getPlainSshCredentials()); + copy.setVagrantConnectionType(getVagrantCredentials()); + copy.setWebDeploymentCredentials(getWebDeploymentCredentials()); + } + + public String getId() { + if (isVagrantConnection()) { + @NotNull VagrantBasedCredentialsHolder cred = getVagrantCredentials(); + + return VAGRANT_PREFIX + cred.getVagrantFolder(); + } + else if (isPlainSshConnection()) { + RemoteCredentials cred = getPlainSshCredentials(); + + return constructSshCredentialsFullPath(cred); + } + else if (isWebDeploymentConnection()) { + WebDeploymentCredentialsHolder cred = getWebDeploymentCredentials(); + return constructSftpCredentialsFullPath(cred.getSshCredentials()); + } + else { + throw unknownConnectionType(); + } + } + + private static String constructSftpCredentialsFullPath(RemoteCredentials cred) { + return SFTP_DEPLOYMENT_PREFIX + cred.getUserName() + "@" + cred.getHost() + ":" + cred.getPort(); + } + + + public static String constructSshCredentialsFullPath(RemoteCredentials cred) { + return RemoteSdkCredentialsHolder.SSH_PREFIX + cred.getUserName() + "@" + cred.getHost() + ":" + cred.getPort(); + } + + public void switchType(RemoteSdkConnectionAcceptor acceptor) { + if (isVagrantConnection()) { + acceptor.vagrant(getVagrantCredentials()); + } + else if (isPlainSshConnection()) { + acceptor.ssh(getPlainSshCredentials()); + } + else if (isWebDeploymentConnection()) { + acceptor.deployment(getWebDeploymentCredentials()); + } + else { + throw unknownConnectionType(); + } + } + + public interface RemoteSdkConnectionAcceptor { + void ssh(RemoteCredentialsHolder cred); + void vagrant(VagrantBasedCredentialsHolder cred); + void deployment(WebDeploymentCredentialsHolder cred); + } +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkAdditionalData2.java b/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkAdditionalData2.java index 92ec30233a6c..c295a42c9598 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkAdditionalData2.java +++ b/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkAdditionalData2.java @@ -19,6 +19,7 @@ import com.intellij.openapi.projectRoots.SdkAdditionalData; import com.intellij.remotesdk.RemoteSdkCredentials; import com.intellij.remotesdk.RemoteSdkCredentialsHolder; import com.intellij.remotesdk.RemoteSdkProperties; +import org.jetbrains.annotations.NotNull; /** * @author traff @@ -33,9 +34,13 @@ public interface RemoteSdkAdditionalData2 String getFullInterpreterPath(); + void setVagrantConnectionType(@NotNull VagrantBasedCredentialsHolder vagrantBasedCredentials); + /** * This method switches to use of ssh-credentials based data * @param credentials credentials that specify connection */ - void setSshCredentials(RemoteSdkCredentialsHolder credentials); + void setSshCredentials(@NotNull RemoteSdkCredentialsHolder credentials); + + void setDeploymentConnectionType(@NotNull WebDeploymentCredentialsHolder credentials); } diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkProducer.java b/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkProducer.java index 72c585b642cd..0178ab8a2752 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkProducer.java +++ b/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkProducer.java @@ -24,7 +24,7 @@ import com.intellij.util.Consumer; public interface RemoteSdkProducer { T getRemoteSdkCredentials() throws InterruptedException; - void produceRemoteSdkCredentials(Consumer remoteSdkConsumer); + void produceRemoteSdkCredentials(Consumer remoteSdkCredentialsConsumer); Object getRemoteSdkDataKey(); } diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/VagrantBasedCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remotesdk2/VagrantBasedCredentialsHolder.java new file mode 100644 index 000000000000..8e9d36f058d1 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remotesdk2/VagrantBasedCredentialsHolder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2014 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.remotesdk2; + +import com.intellij.openapi.util.text.StringUtil; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; + +/** +* @author traff +*/ +public class VagrantBasedCredentialsHolder { + private static final String VAGRANT_FOLDER = "VAGRANT_FOLDER"; + private String myVagrantFolder; + + public VagrantBasedCredentialsHolder() { + } + + public VagrantBasedCredentialsHolder(@NotNull String folder) { + myVagrantFolder = folder; + } + + public void setVagrantFolder(String vagrantFolder) { + myVagrantFolder = vagrantFolder; + } + + @NotNull + public String getVagrantFolder() { + return myVagrantFolder; + } + + public void load(Element element) { + setVagrantFolder(element.getAttributeValue(VAGRANT_FOLDER)); + } + + public void save(Element element) { + element.setAttribute(VAGRANT_FOLDER, getVagrantFolder()); + } +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/WebDeploymentCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remotesdk2/WebDeploymentCredentialsHolder.java new file mode 100644 index 000000000000..d43d0cb4ece3 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remotesdk2/WebDeploymentCredentialsHolder.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 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.remotesdk2; + +import com.intellij.remotesdk.RemoteCredentials; +import com.intellij.remotesdk.RemoteCredentialsHolder; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; + +/** + * @author traff + */ +public class WebDeploymentCredentialsHolder { + public static final String WEB_SERVER_CONFIG_ID = "WEB_SERVER_CONFIG_ID"; + + private String myWebServerConfigId; + private final RemoteCredentialsHolder myRemoteCredentials = new RemoteCredentialsHolder(); + + + public WebDeploymentCredentialsHolder() { + } + + public WebDeploymentCredentialsHolder(@NotNull String webServerConfigId, @NotNull RemoteCredentials remoteCredentials) { + myWebServerConfigId = webServerConfigId; + myRemoteCredentials.copyFrom(remoteCredentials); + } + + @NotNull + public String getWebServerConfigId() { + return myWebServerConfigId; + } + + public void setWebServerConfigId(@NotNull String webServerConfigId) { + myWebServerConfigId = webServerConfigId; + } + + public void load(Element element) { + myRemoteCredentials.load(element); + setWebServerConfigId(element.getAttributeValue(WEB_SERVER_CONFIG_ID)); + } + + public void save(Element element) { + element.setAttribute(WEB_SERVER_CONFIG_ID, getWebServerConfigId()); + + myRemoteCredentials.save(element); + } + + public RemoteCredentials getSshCredentials() { + return myRemoteCredentials; + } +} diff --git a/platform/platform-resources-en/src/messages/DiffBundle.properties b/platform/platform-resources-en/src/messages/DiffBundle.properties index 66a7bab05489..043f6f2231fd 100644 --- a/platform/platform-resources-en/src/messages/DiffBundle.properties +++ b/platform/platform-resources-en/src/messages/DiffBundle.properties @@ -32,7 +32,7 @@ diff.acton.ignore.whitespace.policy.do.not.ignore=Do not ignore diff.acton.ignore.whitespace.policy.leading.and.trailing=Leading and trailing diff.acton.ignore.whitespace.policy.all=All ignore.whitespace.acton.name=Ignore whitespace: -ignore.whitespace.action.not.available.action.name= +diff.panel.combo.box.action.not.available.action.name= diff.dialog.select.change.action.name=Select Change diff.dialog.select.change.action.description=Select changed text in this version and corresponding in other merge.files.dialog.title=Merge @@ -88,5 +88,4 @@ diff.can.not.show.unknown=Can not show diff for unknown file type diff.acton.highlight.mode.action.by.word=By Word diff.acton.highlight.mode.action.by.line=By Line diff.acton.highlight.mode.action.no.highlighting=No Highlighting -diff.acton.highlight.mode.not.available.action.name= diff.acton.highlight.mode.action.name=Highlighting Mode: diff --git a/platform/platform-resources/src/DefaultColorSchemesManager.xml b/platform/platform-resources/src/DefaultColorSchemesManager.xml index d43993b72313..b3f6d7f21226 100644 --- a/platform/platform-resources/src/DefaultColorSchemesManager.xml +++ b/platform/platform-resources/src/DefaultColorSchemesManager.xml @@ -416,20 +416,6 @@ - -

extends XBreakpointBase, P, LineBreakpointState

> implements XLineBreakpoint

{ - @Nullable private RangeHighlighter myHighlighter; + @Nullable private RangeHighlighterEx myHighlighter; private final XLineBreakpointType

myType; private XSourcePosition mySourcePosition; private boolean myDisposed; @@ -86,25 +87,37 @@ public class XLineBreakpointImpl

extends XBreak EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); TextAttributes attributes = scheme.getAttributes(DebuggerColors.BREAKPOINT_ATTRIBUTES); - RangeHighlighter highlighter = myHighlighter; - if (highlighter != null && highlighter.isValid() && document.getLineNumber(highlighter.getStartOffset()) != getLine()) { + RangeHighlighterEx highlighter = myHighlighter; + if (highlighter != null && (!highlighter.isValid() || document.getLineNumber(highlighter.getStartOffset()) != getLine())) { highlighter.dispose(); myHighlighter = null; highlighter = null; } + MarkupModelEx markupModel; if (highlighter == null) { - MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), true); + markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), true); highlighter = markupModel.addPersistentLineHighlighter(getLine(), DebuggerColors.BREAKPOINT_HIGHLIGHTER_LAYER, attributes); - if (highlighter != null) { - highlighter.setGutterIconRenderer(createGutterIconRenderer()); - highlighter.putUserData(DebuggerColors.BREAKPOINT_HIGHLIGHTER_KEY, Boolean.TRUE); - myHighlighter = highlighter; + if (highlighter == null) { + return; } + + highlighter.setGutterIconRenderer(createGutterIconRenderer()); + highlighter.putUserData(DebuggerColors.BREAKPOINT_HIGHLIGHTER_KEY, Boolean.TRUE); + myHighlighter = highlighter; + } + else { + markupModel = null; } - if (highlighter != null) { - updateIcon(); + updateIcon(); + + if (markupModel == null) { + markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), false); + if (markupModel != null) { + // renderersChanged false — we don't change gutter size + markupModel.fireAttributesChanged(highlighter, false); + } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index eca27bdaf661..4becc9723a65 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -2489,6 +2489,9 @@ + #ref doesn''t match regex ''{0}'' #loc local.variable.naming.convention.ignore.option=Ignore for-loop parameters local.variable.naming.convention.ignore.catch.option=Ignore 'catch' block parameters -method.names.differ.only.by.case.problem.descriptor=Method names #ref and ''{0}'' differ only by case #loc +method.names.differ.only.by.case.problem.descriptor=Method name #ref and method name ''{0}'' differ only by case #loc parameter.name.differs.from.overridden.parameter.ignore.character.option=Ignore if overridden parameter contains only one character parameter.name.differs.from.overridden.parameter.ignore.library.option=Ignore if overridden parameter is from a library parameter.name.differs.from.overridden.parameter.problem.descriptor=Parameter name #ref is different from parameter ''{0}'' overridden #loc @@ -2068,4 +2068,6 @@ interface.may.be.annotated.functional.problem.descriptor=Interface #ref#ref hides field in class ''{0}'' #loc +shared.thread.local.random.display.name='ThreadLocalRandom' instance might be shared +shared.thread.local.random.problem.descriptor='ThreadLocalRandom' instance might be shared between threads diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java index c14da9f55373..3ceca68b1458 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java @@ -153,86 +153,59 @@ public class ExpectedTypeUtils { } @Override - public void visitBinaryExpression(@NotNull PsiBinaryExpression binaryExpression) { - final PsiExpression rhs = binaryExpression.getROperand(); - if (rhs == null) { - expectedType = null; - return; + public void visitPolyadicExpression(@NotNull PsiPolyadicExpression polyadicExpression) { + final PsiExpression[] operands = polyadicExpression.getOperands(); + for (PsiExpression operand : operands) { + if (operand == null || operand.getType() == null) { + expectedType = null; + return; + } } - final PsiExpression lhs = binaryExpression.getLOperand(); - PsiType lhsType = lhs.getType(); - if (lhsType == null) { - expectedType = null; - return; - } - PsiType rhsType = rhs.getType(); - if (rhsType == null) { - expectedType = null; - return; - } - final IElementType tokenType = binaryExpression.getOperationTokenType(); - final PsiType type = binaryExpression.getType(); + final IElementType tokenType = polyadicExpression.getOperationTokenType(); + final PsiType type = polyadicExpression.getType(); + final PsiType wrappedExpressionType = wrappedExpression.getType(); if (TypeUtils.isJavaLangString(type) || isArithmeticOperation(tokenType) || isBooleanOperation(tokenType)) { expectedType = type; } else if (isShiftOperation(tokenType)) { - if (lhs == wrappedExpression) { - expectedType = unaryNumericPromotion(lhsType); - } - else { - expectedType = unaryNumericPromotion(rhsType); - } + expectedType = unaryNumericPromotion(wrappedExpressionType); } - else if (ComparisonUtils.isEqualityComparison(binaryExpression)) { + else if (ComparisonUtils.isEqualityComparison(polyadicExpression)) { // JLS 15.21.1 Numerical Equality Operators == and != - final PsiType wrappedExpressionType = wrappedExpression.getType(); if (TypeConversionUtil.isPrimitiveAndNotNull(wrappedExpressionType)) { expectedType = wrappedExpressionType; - return; } - if (lhs == wrappedExpression) { - if (TypeConversionUtil.isPrimitiveAndNotNull(rhsType)) { + else if (operands.length > 2) { + expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); + } + else if (operands[0] == wrappedExpression) { + if (TypeConversionUtil.isPrimitiveAndNotNull(operands[1].getType())) { expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); - return; } - expectedType = TypeUtils.getObjectType(wrappedExpression); + else { + expectedType = TypeUtils.getObjectType(wrappedExpression); + } } else { - if (TypeConversionUtil.isPrimitiveAndNotNull(lhsType)) { + if (TypeConversionUtil.isPrimitiveAndNotNull(operands[0].getType())) { expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); - return; - } - expectedType = TypeUtils.getObjectType(wrappedExpression); + } + else { + expectedType = TypeUtils.getObjectType(wrappedExpression); + } } } else if (ComparisonUtils.isComparisonOperation(tokenType)) { - if (lhs == wrappedExpression && !TypeConversionUtil.isPrimitiveAndNotNull(lhsType)) { - lhsType = PsiPrimitiveType.getUnboxedType(lhsType); - if (lhsType == null) { - expectedType = null; + if (operands.length > 2) { + expectedType = null; + return; + } + else if (!TypeConversionUtil.isPrimitiveAndNotNull(wrappedExpressionType)) { + if (PsiPrimitiveType.getUnboxedType(wrappedExpressionType) == null) { return; } } - if (rhs == wrappedExpression && !TypeConversionUtil.isPrimitiveAndNotNull(rhsType)) { - rhsType = PsiPrimitiveType.getUnboxedType(rhsType); - if (rhsType == null) { - expectedType = null; - return; - } - } - // JLS 5.6.2 Binary Numeric Promotion - if (PsiType.DOUBLE.equals(lhsType) || PsiType.DOUBLE.equals(rhsType)) { - expectedType = PsiType.DOUBLE; - } - else if (PsiType.FLOAT.equals(lhsType) || PsiType.FLOAT.equals(rhsType)) { - expectedType = PsiType.FLOAT; - } - else if (PsiType.LONG.equals(lhsType) || PsiType.LONG.equals(rhsType)) { - expectedType = PsiType.LONG; - } - else { - expectedType = PsiType.INT; - } + expectedType = TypeConversionUtil.binaryNumericPromotion(operands[0].getType(), operands[1].getType()); } else { expectedType = null; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java new file mode 100644 index 000000000000..97adc033c5b1 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java @@ -0,0 +1,122 @@ +/* + * Copyright 2000-2014 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.siyeh.ig.threading; + +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class SharedThreadLocalRandomInspection extends BaseInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("shared.thread.local.random.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("shared.thread.local.random.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new SharedThreadLocalRandomVisitor(); + } + + private static class SharedThreadLocalRandomVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + @NonNls final String name = methodExpression.getReferenceName(); + if (!"current".equals(name)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (!InheritanceUtil.isInheritor(aClass, "java.util.concurrent.ThreadLocalRandom")) { + return; + } + if (isArgumentToMethodCall(expression)) { + registerMethodCallError(expression); + } + else { + final PsiVariable variable = assignedToVariable(expression); + if (variable instanceof PsiField) { + registerMethodCallError(expression); + } + else if (variable instanceof PsiLocalVariable) { + final PsiCodeBlock context = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, context) || + VariableAccessUtils.variableIsUsedInInnerClass(variable, context)) { + registerMethodCallError(expression); + } + } + } + } + + private static boolean isArgumentToMethodCall(PsiExpression expression) { + final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression); + if (!(parent instanceof PsiExpressionList)) { + return false; + } + final PsiElement grandParent = parent.getParent(); + return grandParent instanceof PsiMethodCallExpression; + } + + private static PsiVariable assignedToVariable(PsiMethodCallExpression expression) { + final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class); + if (parent instanceof PsiVariable) { + return (PsiVariable)parent; + } + if (!(parent instanceof PsiAssignmentExpression)) { + return null; + } + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent; + final PsiExpression rhs = assignmentExpression.getRExpression(); + if (!PsiTreeUtil.isAncestor(rhs, expression, false)) { + return null; + } + final PsiExpression lhs = ParenthesesUtils.stripParentheses(assignmentExpression.getLExpression()); + if (!(lhs instanceof PsiReferenceExpression)) { + return null; + } + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs; + final PsiElement target = referenceExpression.resolve(); + if (!(target instanceof PsiVariable)) { + return null; + } + return (PsiVariable)target; + } + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SharedThreadLocalRandom.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SharedThreadLocalRandom.html new file mode 100644 index 000000000000..07ebccab4653 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SharedThreadLocalRandom.html @@ -0,0 +1,15 @@ + + +Reports java.util.concurrent.ThreadLocalRandom instances which might be shared between threads. +A ThreadLocalRandom might be shared between threads and is reported when it is assigned to a field, +used as a method argument or assigned to a local variable and used in anonymous or nested classes. +A ThreadLocalRandom should not be shared between threads because that is not thread-safe. +

+Usages of ThreadLocalRandom should typically look like ThreadLocalRandom.current().nextInt(...) +(or nextDouble(...) etc.). +When all usages are in this form, ThreadLocalRandom instances can not be used accidentally by multiple threads. + +

+New in 13.1 + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html index 2cb9e55aa170..e78d9c1e5afe 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html @@ -1,5 +1,6 @@ +Reports fields of type java.lang.ThreadLocal which are not declared static final. In the most common case a java.lang.ThreadLocal instance associates state with a thread. A non-static non-final java.lang.ThreadLocal field associates state with diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java index a39bd53e4407..e598f0758a64 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java @@ -59,4 +59,8 @@ public class AutoUnboxing { if ((boolean) b) {} if ((int)n) {} } + + boolean polyadic() { + return true && Boolean.TRUE && true; + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml index 431f5ca55078..a1ceb62b0486 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml @@ -106,4 +106,10 @@ Auto-unboxing <code>n</code> #loc + + AutoUnboxing.java + 64 + Auto-unboxing + Auto-unboxing <code>Boolean.TRUE</code> #loc + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml index 570e237c7063..3c9a518635fc 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml @@ -4,35 +4,35 @@ MethodNamesDifferOnlyByCase.java 20 Method names differing only by case - Method names <code>hashcode</code> and 'hashCode' differ only by case #loc + Method name <code>hashcode</code> and method name 'hashCode' differ only by case #loc MethodNamesDifferOnlyByCase.java 30 Method names differing only by case - Method names <code>xX</code> and 'xx' differ only by case #loc + Method name <code>xX</code> and method name 'xx' differ only by case #loc MethodNamesDifferOnlyByCase.java 5 Method names differing only by case - Method names <code>fooBar</code> and 'fooBAr' differ only by case #loc + Method name <code>fooBar</code> and method name 'fooBAr' differ only by case #loc MethodNamesDifferOnlyByCase.java 10 Method names differing only by case - Method names <code>fooBAr</code> and 'fooBar' differ only by case #loc + Method name <code>fooBAr</code> and method name 'fooBar' differ only by case #loc MethodNamesDifferOnlyByCase.java 29 Method names differing only by case - Method names <code>xx</code> and 'xX' differ only by case #loc + Method name <code>xx</code> and method name 'xX' differ only by case #loc \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/SharedThreadLocalRandomInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/SharedThreadLocalRandomInspectionTest.java new file mode 100644 index 000000000000..b15bc350fd6b --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/SharedThreadLocalRandomInspectionTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2014 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.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; + +/** + * @author Bas Leijdekkers + */ +public class SharedThreadLocalRandomInspectionTest extends LightInspectionTestCase { + @Override + protected InspectionProfileEntry getInspection() { + return new SharedThreadLocalRandomInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package java.util.concurrent;\n" + + "import java.util.Random;" + + "public class ThreadLocalRandom extends Random {" + + " public static ThreadLocalRandom current() {" + + " return null;" + + " }" + + "}" + }; + } + + public void testNoWarn() { + doStatementTest("System.out.println(java.util.concurrent.ThreadLocalRandom.current().nextInt());"); + } + + public void testArgument() { + doStatementTest("System.out.println(java.util.concurrent.ThreadLocalRandom./*'ThreadLocalRandom' instance might be shared between threads*/current/**/());"); + } + + public void testNoWarn2() { + doMemberTest("void m() {" + + " java.util.concurrent.ThreadLocalRandom r = java.util.concurrent.ThreadLocalRandom.current();" + + "}"); + } + + public void testNestedClass() { + doMemberTest("void m() {" + + " java.util.concurrent.ThreadLocalRandom r = java.util.concurrent.ThreadLocalRandom./*'ThreadLocalRandom' instance might be shared between threads*/current/**/();" + + " class Z extends Thread {" + + " public void run() {" + + " System.out.println(r.nextInt(1));" + + " }" + + " }" + + "}"); + } + + public void testAssignmentToField() { + doTest("import java.util.concurrent.ThreadLocalRandom;" + + "class A {" + + " private ThreadLocalRandom r;" + + " void m() {" + + " r = ThreadLocalRandom./*'ThreadLocalRandom' instance might be shared between threads*/current/**/();" + + " }" + + "}"); + } +} diff --git a/plugins/IntelliLang/src/META-INF/plugin.xml b/plugins/IntelliLang/src/META-INF/plugin.xml index 34731356c845..b62e139cc20e 100644 --- a/plugins/IntelliLang/src/META-INF/plugin.xml +++ b/plugins/IntelliLang/src/META-INF/plugin.xml @@ -2,7 +2,19 @@ IntelliLang org.intellij.intelliLang JetBrains - + + +

  • Language injection
  • +
  • Pattern validation
  • +
  • Regular expression support
  • +
  • Language Injections page in the Settings/Preferences dialog.
  • +
  • Ability to edit injected code in the special scratch-pad editor. + + ]]> + 8.0 XPathView diff --git a/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.java b/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.java index be3dc676245b..6c8e413fae95 100644 --- a/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.java +++ b/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -98,11 +98,13 @@ public class AntImportsIndex extends ScalarIndexExtension{ return DATA_INDEXER; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML); diff --git a/plugins/devkit/src/references/IconsReferencesContributor.java b/plugins/devkit/src/references/IconsReferencesContributor.java index 74d258783660..eac85d8f0f3c 100644 --- a/plugins/devkit/src/references/IconsReferencesContributor.java +++ b/plugins/devkit/src/references/IconsReferencesContributor.java @@ -299,7 +299,7 @@ public class IconsReferencesContributor extends PsiReferenceContributor implemen model.setCaseSensitive(true); model.setFindAll(true); model.setWholeWordsOnly(true); - FindInProjectUtil.findUsages(model, FindInProjectUtil.getPsiDirectory(model, project), project, false, new Processor() { + FindInProjectUtil.findUsages(model, FindInProjectUtil.getPsiDirectory(model, project), project, new Processor() { @Override public boolean process(final UsageInfo usage) { ApplicationManager.getApplication().runReadAction(new Runnable() { diff --git a/plugins/eclipse/resources/META-INF/plugin.xml b/plugins/eclipse/resources/META-INF/plugin.xml index b3cd54debe52..a3f76504c14c 100644 --- a/plugins/eclipse/resources/META-INF/plugin.xml +++ b/plugins/eclipse/resources/META-INF/plugin.xml @@ -1,7 +1,20 @@ Eclipse Integration org.jetbrains.idea.eclipse - Provides possibility to import, export and synchronize Eclipse project files + + +
  • Open Eclipse project in IntelliJ IDEA
  • +
  • Import Eclipse project into IntelliJ IDEA
  • +
  • Export IntelliJ IDEA project into Eclipse
  • +
  • Convert IntelliJ IDEA module to Eclipse-compatible format
  • +
  • Synchronize Eclipse project files
  • + +

    + ]]> + + 3.0 JetBrains s.r.o. diff --git a/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java b/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java index 2afb3c821223..89ccaa51d195 100644 --- a/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java +++ b/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java @@ -1,9 +1,12 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -88,7 +91,7 @@ public class NewGitUsersComponent { private static class MyDataExternalizer implements DataExternalizer> { @Override - public List read(DataInput in) throws IOException { + public List read(@NotNull DataInput in) throws IOException { final int size = in.readInt(); final ArrayList result = new ArrayList(size); for (int i = 0; i < size; i++) { @@ -98,7 +101,7 @@ public class NewGitUsersComponent { } @Override - public void save(DataOutput out, List value) throws IOException { + public void save(@NotNull DataOutput out, List value) throws IOException { out.writeInt(value.size()); for (String s : value) { out.writeUTF(s); diff --git a/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.java b/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.java index 70239c1b1a5d..0c69e45f6ae2 100644 --- a/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.java +++ b/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -39,6 +39,7 @@ import com.intellij.util.io.EnumeratorStringDescriptor; import git4idea.GitRevisionNumber; import git4idea.history.GitHistoryUtils; import git4idea.history.browser.SHAHash; +import org.jetbrains.annotations.NotNull; import java.io.*; import java.util.*; @@ -120,12 +121,12 @@ public class GitCommitsSequentialIndex implements GitCommitsSequentially { private DataExternalizer createExternalizer() { return new DataExternalizer() { @Override - public void save(DataOutput out, String value) throws IOException { + public void save(@NotNull DataOutput out, String value) throws IOException { out.writeUTF(value); } @Override - public String read(DataInput in) throws IOException { + public String read(@NotNull DataInput in) throws IOException { return in.readUTF(); } }; diff --git a/plugins/github/src/META-INF/plugin.xml b/plugins/github/src/META-INF/plugin.xml index e0345633a81d..8baf48bf6eee 100644 --- a/plugins/github/src/META-INF/plugin.xml +++ b/plugins/github/src/META-INF/plugin.xml @@ -2,7 +2,17 @@ GitHub org.jetbrains.plugins.github JetBrains - GitHub integration + + GitHub. + The following features are available: +

      +
    • Dedicated page under the Version Control node in the Settings/Preferences dialog.
    • +
    • Ability to browse, check out sources from and import into the available Git repositories, when GitHub is not enabled.
    • +
    • When GitHub is enabled, the GitHub node appears on the VCS menu, and on the context menu of the editor. +
    + ]]> + com.intellij.modules.lang Git4Idea diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java index 878b9b855a0c..600f484f0c0b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vfs.VirtualFile; @@ -41,12 +42,14 @@ import org.jetbrains.plugins.github.api.GithubGist; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.ui.GithubCreateGistDialog; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubNotifications; import org.jetbrains.plugins.github.util.GithubUtil; import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import static org.jetbrains.plugins.github.api.GithubGist.FileContent; @@ -110,33 +113,24 @@ public class GithubCreateGistAction extends DumbAwareAction { return; } - GithubAuthData auth = GithubAuthData.createAnonymous(); - if (!dialog.isAnonymous()) { - try { - auth = getValidAuthData(project); - } - catch (GithubOperationCanceledException e) { - return; - } - catch (IOException e) { - GithubNotifications.showError(project, "Can't create gist", e); - return; - } + final GithubAuthDataHolder authHolder = getValidAuthData(project, dialog.isAnonymous()); + if (authHolder == null) { + return; } - final AtomicReference url = new AtomicReference(); - final GithubAuthData finalAuth = auth; + final Ref url = new Ref(); new Task.Backgroundable(project, "Creating Gist...") { @Override public void run(@NotNull ProgressIndicator indicator) { List contents = collectContents(project, editor, file, files); - String gistUrl = createGist(project, finalAuth, contents, dialog.isPrivate(), dialog.getDescription(), dialog.getFileName()); + String gistUrl = + createGist(project, authHolder, indicator, contents, dialog.isPrivate(), dialog.getDescription(), dialog.getFileName()); url.set(gistUrl); } @Override public void onSuccess() { - if (url.get() == null) { + if (url.isNull()) { return; } if (dialog.isOpenInBrowser()) { @@ -149,17 +143,32 @@ public class GithubCreateGistAction extends DumbAwareAction { }.queue(); } - @NotNull - private static GithubAuthData getValidAuthData(@NotNull final Project project) throws IOException { - return GithubUtil.computeValueInModal(project, "Access to GitHub", - new ThrowableConvertor() { - @NotNull - @Override - public GithubAuthData convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.getValidAuthDataFromConfig(project, indicator); - } - } - ); + @Nullable + private static GithubAuthDataHolder getValidAuthData(@NotNull final Project project, boolean isAnonymous) { + if (isAnonymous) { + return new GithubAuthDataHolder(GithubAuthData.createAnonymous()); + } + else { + try { + return GithubUtil + .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { + @NotNull + @Override + public GithubAuthDataHolder convert(ProgressIndicator indicator) throws IOException { + return GithubUtil.getValidAuthDataHolderFromConfig(project, indicator); + } + } + ); + } + catch (GithubOperationCanceledException e) { + return null; + } + catch (IOException e) { + GithubNotifications.showError(project, "Can't create gist", e); + return null; + } + + } } @NotNull @@ -197,10 +206,11 @@ public class GithubCreateGistAction extends DumbAwareAction { @Nullable static String createGist(@NotNull Project project, - @NotNull GithubAuthData auth, + @NotNull GithubAuthDataHolder auth, + @NotNull ProgressIndicator indicator, @NotNull List contents, - boolean isPrivate, - @NotNull String description, + final boolean isPrivate, + @NotNull final String description, @Nullable String filename) { if (contents.isEmpty()) { GithubNotifications.showWarning(project, FAILED_TO_CREATE_GIST, "Can't create empty gist"); @@ -211,8 +221,14 @@ public class GithubCreateGistAction extends DumbAwareAction { contents = Collections.singletonList(new FileContent(filename, entry.getContent())); } try { - GithubGist gist = GithubApiUtil.createGist(auth, contents, description, isPrivate); - return gist.getHtmlUrl(); + final List finalContents = contents; + return GithubUtil.runTask(project, auth, indicator, new ThrowableConvertor() { + @NotNull + @Override + public GithubGist convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.createGist(auth, finalContents, description, isPrivate); + } + }).getHtmlUrl(); } catch (IOException e) { GithubNotifications.showError(project, FAILED_TO_CREATE_GIST, e); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index ee357b145601..d06851c89b97 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -8,6 +8,7 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; @@ -37,17 +38,13 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.*; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.ui.GithubSelectForkDialog; -import org.jetbrains.plugins.github.util.GithubAuthData; -import org.jetbrains.plugins.github.util.GithubNotifications; -import org.jetbrains.plugins.github.util.GithubUrlUtil; -import org.jetbrains.plugins.github.util.GithubUtil; +import org.jetbrains.plugins.github.util.*; import java.io.IOException; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; -import java.util.concurrent.atomic.AtomicReference; /** * @author Aleksey Pivovarov @@ -63,7 +60,7 @@ public class GithubCreatePullRequestWorker { @NotNull private final String myRemoteName; @NotNull private final String myRemoteUrl; @NotNull private final String myCurrentBranch; - @NotNull private final GithubAuthData myAuth; + @NotNull private final GithubAuthDataHolder myAuthHolder; @NotNull private final Map> myDiffInfos; @@ -77,7 +74,7 @@ public class GithubCreatePullRequestWorker { @NotNull String remoteName, @NotNull String remoteUrl, @NotNull String currentBranch, - @NotNull GithubAuthData auth) { + @NotNull GithubAuthDataHolder authHolder) { myProject = project; myGit = git; myGitRepository = gitRepository; @@ -85,7 +82,7 @@ public class GithubCreatePullRequestWorker { myRemoteName = remoteName; myRemoteUrl = remoteUrl; myCurrentBranch = currentBranch; - myAuth = auth; + myAuthHolder = authHolder; myDiffInfos = new HashMap>(); } @@ -134,14 +131,14 @@ public class GithubCreatePullRequestWorker { return null; } - GithubAuthData auth; + GithubAuthDataHolder authHolder; try { - auth = GithubUtil - .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { + authHolder = GithubUtil + .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { @NotNull @Override - public GithubAuthData convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.getValidAuthDataFromConfig(project, indicator); + public GithubAuthDataHolder convert(ProgressIndicator indicator) throws IOException { + return GithubUtil.getValidAuthDataHolderFromConfig(project, indicator); } }); } @@ -153,7 +150,7 @@ public class GithubCreatePullRequestWorker { return null; } - return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName(), auth); + return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName(), authHolder); } @Nullable @@ -168,7 +165,7 @@ public class GithubCreatePullRequestWorker { GitRemote targetRemote = GithubUtil.findGithubRemote(myGitRepository, forkPath); String targetRemoteName = targetRemote == null ? null : targetRemote.getName(); if (targetRemoteName == null) { - final AtomicReference responseRef = new AtomicReference(); + final Ref responseRef = new Ref(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { @@ -182,13 +179,21 @@ public class GithubCreatePullRequestWorker { } // load available branches - List branches = ContainerUtil.map(GithubApiUtil.getRepoBranches(myAuth, forkPath.getUser(), forkPath.getRepository()), - new Function() { - @Override - public String fun(GithubBranch githubBranch) { - return githubBranch.getName(); - } - }); + List branches = ContainerUtil.map(GithubUtil.runTask(myProject, myAuthHolder, indicator, + new ThrowableConvertor, IOException>() { + @Override + public List convert(@NotNull GithubAuthData auth) + throws IOException { + return GithubApiUtil.getRepoBranches(auth, forkPath.getUser(), + forkPath.getRepository()); + } + } + ), new Function() { + @Override + public String fun(GithubBranch githubBranch) { + return githubBranch.getName(); + } + }); // fetch if (targetRemoteName != null) { @@ -251,7 +256,7 @@ public class GithubCreatePullRequestWorker { @Nullable public GithubFullPath showTargetDialog(boolean firstTime) { - final GithubInfo2 info = getAvailableForksInModal(myProject, myGitRepository, myAuth, myPath); + final GithubInfo2 info = getAvailableForksInModal(myProject, myGitRepository, myAuthHolder, myPath); if (info == null) { return null; } @@ -281,8 +286,8 @@ public class GithubCreatePullRequestWorker { return GithubUtil.computeValueInModal(myProject, "Access to GitHub", new Convertor() { @Nullable @Override - public GithubFullPath convert(ProgressIndicator o) { - return findRepositoryByUser(myProject, user, info.getForks(), myAuth, info.getSource()); + public GithubFullPath convert(ProgressIndicator indicator) { + return findRepositoryByUser(myProject, myAuthHolder, indicator, user, info.getForks(), info.getSource()); } }); } @@ -301,8 +306,11 @@ public class GithubCreatePullRequestWorker { return true; } if (info.getInfo().getBranchToHeadCommits(myGitRepository).isEmpty()) { - GithubNotifications.showWarningDialog(myProject, CANNOT_CREATE_PULL_REQUEST, - "Can't create empty pull request: the branch" + getCurrentBranch() + " in fully merged to the branch " + targetBranch + "."); + GithubNotifications.showWarningDialog(myProject, CANNOT_CREATE_PULL_REQUEST, "Can't create empty pull request: the branch" + + getCurrentBranch() + + " in fully merged to the branch " + + targetBranch + + "."); return false; } if (info.getInfo().getHeadToBranchCommits(myGitRepository).isEmpty()) { @@ -332,7 +340,8 @@ public class GithubCreatePullRequestWorker { LOG.info("Creating pull request"); indicator.setText("Creating pull request..."); - GithubPullRequest request = createPullRequest(project, myAuth, myForkPath, title, description, headBranch, targetBranch); + GithubPullRequest request = + createPullRequest(project, myAuthHolder, indicator, myForkPath, title, description, headBranch, targetBranch); if (request == null) { return; } @@ -357,14 +366,21 @@ public class GithubCreatePullRequestWorker { @Nullable private static GithubPullRequest createPullRequest(@NotNull Project project, - @NotNull GithubAuthData auth, - @NotNull GithubFullPath targetRepo, - @NotNull String title, - @NotNull String description, - @NotNull String head, - @NotNull String base) { + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull final GithubFullPath targetRepo, + @NotNull final String title, + @NotNull final String description, + @NotNull final String head, + @NotNull final String base) { try { - return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, head, base); + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor() { + @NotNull + @Override + public GithubPullRequest convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, head, base); + } + }); } catch (IOException e) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e); @@ -451,7 +467,7 @@ public class GithubCreatePullRequestWorker { @Nullable private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project, @NotNull final GitRepository gitRepository, - @NotNull final GithubAuthData auth, + @NotNull final GithubAuthDataHolder authHolder, @NotNull final GithubFullPath path) { try { return GithubUtil @@ -462,7 +478,15 @@ public class GithubCreatePullRequestWorker { final Set forks = new HashSet(); // GitHub - GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(auth, path.getUser(), path.getRepository()); + GithubRepoDetailed repo = + GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor() { + @NotNull + @Override + public GithubRepoDetailed convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getDetailedRepoInfo(auth, path.getUser(), path.getRepository()); + } + }); + forks.add(path); if (repo.getParent() != null) { forks.add(repo.getParent().getFullPath()); @@ -507,10 +531,11 @@ public class GithubCreatePullRequestWorker { @Nullable private static GithubFullPath findRepositoryByUser(@NotNull Project project, - @NotNull String user, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull final String user, @NotNull Set forks, - @NotNull GithubAuthData auth, - @NotNull GithubRepo source) { + @NotNull final GithubRepo source) { for (GithubFullPath path : forks) { if (StringUtil.equalsIgnoreCase(user, path.getUser())) { return path; @@ -518,20 +543,28 @@ public class GithubCreatePullRequestWorker { } try { - GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(auth, user, source.getName()); - if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), source.getUserName())) { - return target.getFullPath(); - } - } - catch (IOException ignore) { - // such repo may not exist - } + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor() { + @Nullable + @Override + public GithubFullPath convert(@NotNull GithubAuthData auth) throws IOException { + try { + GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(auth, user, source.getName()); + if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), source.getUserName())) { + return target.getFullPath(); + } + } + catch (IOException ignore) { + // such repo may not exist + } - try { - GithubRepo fork = GithubApiUtil.findForkByUser(auth, source.getUserName(), source.getName(), user); - if (fork != null) { - return fork.getFullPath(); - } + GithubRepo fork = GithubApiUtil.findForkByUser(auth, source.getUserName(), source.getName(), user); + if (fork != null) { + return fork.getFullPath(); + } + + return null; + } + }); } catch (IOException e) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java index d3f912545ee2..4faaf7bf568f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java @@ -105,7 +105,6 @@ public class GithubRebaseAction extends DumbAwareAction { GithubNotifications.showError(project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find git repository"); return; } - BasicAction.saveAll(); new Task.Backgroundable(project, "Rebasing GitHub fork...") { @@ -175,15 +174,16 @@ public class GithubRebaseAction extends DumbAwareAction { if (GithubUtil.addGithubRemote(project, gitRepository, "upstream", parentRepoUrl)) { return parentRepoUrl; - } else { + } + else { return null; } } @Nullable private static GithubRepoDetailed loadRepositoryInfo(@NotNull Project project, - @NotNull GitRepository gitRepository, - @NotNull ProgressIndicator indicator) { + @NotNull GitRepository gitRepository, + @NotNull ProgressIndicator indicator) { final String remoteUrl = GithubUtil.findGithubRemoteUrl(gitRepository); if (remoteUrl == null) { GithubNotifications.showError(project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find github remote"); @@ -196,13 +196,14 @@ public class GithubRebaseAction extends DumbAwareAction { } try { - return GithubUtil.runWithValidAuth(project, indicator, new ThrowableConvertor() { - @Override - @NotNull - public GithubRepoDetailed convert(GithubAuthData authData) throws IOException { - return GithubApiUtil.getDetailedRepoInfo(authData, userAndRepo.getUser(), userAndRepo.getRepository()); - } - }); + return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator, + new ThrowableConvertor() { + @NotNull + @Override + public GithubRepoDetailed convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getDetailedRepoInfo(auth, userAndRepo.getUser(), userAndRepo.getRepository()); + } + }); } catch (GithubOperationCanceledException e) { return null; @@ -236,7 +237,8 @@ public class GithubRebaseAction extends DumbAwareAction { public void run() { doRebaseCurrentBranch(project, gitRepository.getRoot(), indicator); } - }); + } + ); process.execute(); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index d3e72a278c0c..99c5ff9020c6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -26,13 +26,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog; import com.intellij.openapi.vcs.ui.CommitMessage; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ThrowableConsumer; import com.intellij.util.ThrowableConvertor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; @@ -51,18 +51,18 @@ import git4idea.util.GitUIUtil; import icons.GithubIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.github.api.*; +import org.jetbrains.plugins.github.api.GithubApiUtil; +import org.jetbrains.plugins.github.api.GithubRepo; +import org.jetbrains.plugins.github.api.GithubUserDetailed; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.ui.GithubShareDialog; -import org.jetbrains.plugins.github.util.GithubAuthData; -import org.jetbrains.plugins.github.util.GithubNotifications; -import org.jetbrains.plugins.github.util.GithubUrlUtil; -import org.jetbrains.plugins.github.util.GithubUtil; +import org.jetbrains.plugins.github.util.*; import javax.swing.*; import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled; @@ -125,8 +125,10 @@ public class GithubShareAction extends DumbAwareAction { externalRemoteDetected = !gitRepository.getRemotes().isEmpty(); } + final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings(); + // get available GitHub repos with modal progress - final GithubInfo githubInfo = loadGithubInfoWithModal(project); + final GithubInfo githubInfo = loadGithubInfoWithModal(authHolder, project); if (githubInfo == null) { return; } @@ -150,7 +152,7 @@ public class GithubShareAction extends DumbAwareAction { // create GitHub repo (network) LOG.info("Creating GitHub repository"); indicator.setText("Creating GitHub repository..."); - final String url = createGithubRepository(project, githubInfo.getAuthData(), name, description, isPrivate); + final String url = createGithubRepository(project, authHolder, indicator, name, description, isPrivate); if (url == null) { return; } @@ -202,29 +204,28 @@ public class GithubShareAction extends DumbAwareAction { } @Nullable - private static GithubInfo loadGithubInfoWithModal(@NotNull final Project project) { + private static GithubInfo loadGithubInfoWithModal(@NotNull final GithubAuthDataHolder authHolder, @NotNull final Project project) { try { return GithubUtil .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { + @NotNull @Override public GithubInfo convert(ProgressIndicator indicator) throws IOException { // get existing github repos (network) and validate auth data - final AtomicReference> availableReposRef = new AtomicReference>(); - final GithubAuthData auth = - GithubUtil.runAndGetValidAuth(project, indicator, new ThrowableConsumer() { - @Override - public void consume(GithubAuthData authData) throws IOException { - availableReposRef.set(GithubApiUtil.getUserRepos(authData)); - } - }); - final HashSet names = new HashSet(); - for (GithubRepo info : availableReposRef.get()) { - names.add(info.getName()); - } + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor() { + @NotNull + @Override + public GithubInfo convert(@NotNull GithubAuthData auth) throws IOException { + // check access to private repos (network) + GithubUserDetailed userInfo = GithubApiUtil.getCurrentUserDetailed(auth); - // check access to private repos (network) - final GithubUserDetailed userInfo = GithubApiUtil.getCurrentUserDetailed(auth); - return new GithubInfo(auth, userInfo, names); + HashSet names = new HashSet(); + for (GithubRepo info : GithubApiUtil.getUserRepos(auth)) { + names.add(info.getName()); + } + return new GithubInfo(userInfo, names); + } + }); } }); } @@ -239,14 +240,20 @@ public class GithubShareAction extends DumbAwareAction { @Nullable private static String createGithubRepository(@NotNull Project project, - @NotNull GithubAuthData auth, - @NotNull String name, - @NotNull String description, - boolean isPrivate) { + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull final String name, + @NotNull final String description, + final boolean isPrivate) { try { - GithubRepo response = GithubApiUtil.createRepo(auth, name, description, isPrivate); - return response.getHtmlUrl(); + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor() { + @NotNull + @Override + public GithubRepo convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.createRepo(auth, name, description, isPrivate); + } + }).getHtmlUrl(); } catch (IOException e) { GithubNotifications.showError(project, "Failed to create GitHub Repository", e); @@ -286,15 +293,15 @@ public class GithubShareAction extends DumbAwareAction { // ask for files to add final List trackedFiles = ChangeListManager.getInstance(project).getAffectedFiles(); - final Collection untrackedFiles = filterOutIgnored(project, - repository.getUntrackedFilesHolder().retrieveUntrackedFiles()); + final Collection untrackedFiles = + filterOutIgnored(project, repository.getUntrackedFilesHolder().retrieveUntrackedFiles()); trackedFiles.removeAll(untrackedFiles); // fix IDEA-119855 final List allFiles = new ArrayList(); allFiles.addAll(trackedFiles); allFiles.addAll(untrackedFiles); - final AtomicReference dialogRef = new AtomicReference(); + final Ref dialogRef = new Ref(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { @@ -429,12 +436,10 @@ public class GithubShareAction extends DumbAwareAction { private static class GithubInfo { @NotNull private final GithubUserDetailed myUser; - @NotNull private final GithubAuthData myAuthData; @NotNull private final HashSet myRepositoryNames; - GithubInfo(@NotNull GithubAuthData auth, @NotNull GithubUserDetailed user, @NotNull HashSet repositoryNames) { + GithubInfo(@NotNull GithubUserDetailed user, @NotNull HashSet repositoryNames) { myUser = user; - myAuthData = auth; myRepositoryNames = repositoryNames; } @@ -443,11 +448,6 @@ public class GithubShareAction extends DumbAwareAction { return myUser; } - @NotNull - public GithubAuthData getAuthData() { - return myAuthData; - } - @NotNull public HashSet getRepositoryNames() { return myRepositoryNames; diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java index ec7d3ae2b51d..581dc16bf25b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java @@ -169,6 +169,10 @@ public class GithubApiUtil { if (tokenAuth != null) { method.addRequestHeader("Authorization", "token " + tokenAuth.getToken()); } + GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth(); + if (basicAuth != null && basicAuth.getCode() != null) { + method.addRequestHeader("X-GitHub-OTP", basicAuth.getCode()); + } for (Header header : headers) { method.addRequestHeader(header); } @@ -401,6 +405,14 @@ public class GithubApiUtil { * Github API */ + public static void askForTwoFactorCodeSMS(@NotNull GithubAuthData auth) { + try { + postRequest(auth, "/authorizations", null, ACCEPT_V3_JSON); + } catch (IOException e) { + LOG.info(e); + } + } + @NotNull public static Collection getTokenScopes(@NotNull GithubAuthData auth) throws IOException { HttpMethod method = null; @@ -448,10 +460,9 @@ public class GithubApiUtil { @NotNull public static String getMasterToken(@NotNull GithubAuthData auth, @Nullable String note) throws IOException { - List scopes = new ArrayList(); - - scopes.add("repo"); // read/write access to public/private repositories - scopes.add("gist"); // create/delete gists + // "repo" - read/write access to public/private repositories + // "gist" - create/delete gists + List scopes = Arrays.asList("repo", "gist"); return getScopedToken(auth, scopes, note); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java index 668913836dbd..ee117b0bdef9 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java @@ -32,6 +32,7 @@ import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.GithubRepo; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubNotifications; import org.jetbrains.plugins.github.util.GithubUtil; @@ -60,12 +61,15 @@ public class GithubCheckoutProvider implements CheckoutProvider { @NotNull @Override public List convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.runWithValidAuth(project, indicator, new ThrowableConvertor, IOException>() { - @Override - public List convert(GithubAuthData authData) throws IOException { - return GithubApiUtil.getAvailableRepos(authData); - } - }); + return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator, + new ThrowableConvertor, IOException>() { + @NotNull + @Override + public List convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getAvailableRepos(auth); + } + } + ); } }); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java index 568a010eaeb6..a340de0f62f1 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java @@ -37,6 +37,9 @@ public class GithubHttpAuthDataProvider implements GitHttpAuthDataProvider { } GithubSettings settings = GithubSettings.getInstance(); + if (!settings.isValidGitAuth()) { + return null; + } String host1 = GithubUrlUtil.getHostFromUrl(settings.getHost()); String host2 = GithubUrlUtil.getHostFromUrl(url); diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java index 8af4136507f5..059be25cb7e3 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java +++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java @@ -13,11 +13,12 @@ import com.intellij.util.ui.FormBuilder; import com.intellij.util.ui.GridBag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubNotifications; import org.jetbrains.plugins.github.util.GithubUtil; -import org.jetbrains.plugins.github.api.GithubApiUtil; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -124,15 +125,19 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor() { - @NotNull - @Override - public String convert(GithubAuthData auth) throws IOException { - return GithubApiUtil.getReadOnlyToken(auth, getRepoAuthor(), getRepoName(), "Intellij tasks plugin"); - } - }); + .runTaskWithBasicAuthForHost(myProject, GithubAuthDataHolder.createFromSettings(), indicator, getHost(), + new ThrowableConvertor() { + @NotNull + @Override + public String convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil + .getReadOnlyToken(auth, getRepoAuthor(), getRepoName(), "Intellij tasks plugin"); + } + } + ); } - })); + }) + ); } catch (GithubOperationCanceledException ignore) { } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java index fac45c597980..80acc787d6c6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java @@ -16,25 +16,17 @@ package org.jetbrains.plugins.github.ui; import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.github.util.GithubAuthData; -import org.jetbrains.plugins.github.util.GithubSettings; /** * @author Aleksey Pivovarov */ public class GithubBasicLoginDialog extends GithubLoginDialog { - public GithubBasicLoginDialog(@Nullable Project project) { - super(project); + public GithubBasicLoginDialog(@NotNull Project project, @NotNull GithubAuthData oldAuthData, @NotNull String host) { + super(project, oldAuthData); myGithubLoginPanel.lockAuthType(GithubAuthData.AuthType.BASIC); - } - - @Override - protected void saveCredentials(GithubAuthData auth) { - final GithubSettings settings = GithubSettings.getInstance(); - if (settings.getAuthType() != GithubAuthData.AuthType.TOKEN) { - settings.setCredentials(myGithubLoginPanel.getHost(), auth, myGithubLoginPanel.isSavePasswordSelected()); - } + myGithubLoginPanel.lockHost(host); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java index 7660fb569b7f..c4e33f6e136c 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java @@ -6,9 +6,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.util.ThrowableConvertor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.GithubUser; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubSettings; import org.jetbrains.plugins.github.util.GithubUtil; @@ -25,18 +25,25 @@ public class GithubLoginDialog extends DialogWrapper { protected final GithubLoginPanel myGithubLoginPanel; protected final GithubSettings mySettings; + protected final Project myProject; - public GithubLoginDialog(@Nullable final Project project) { + protected GithubAuthData myAuthData; + + public GithubLoginDialog(@NotNull final Project project, @NotNull GithubAuthData oldAuthData) { super(project, true); myProject = project; + myGithubLoginPanel = new GithubLoginPanel(this); - mySettings = GithubSettings.getInstance(); - myGithubLoginPanel.setHost(mySettings.getHost()); - myGithubLoginPanel.setLogin(mySettings.getLogin()); - myGithubLoginPanel.setAuthType(mySettings.getAuthType()); + myGithubLoginPanel.setHost(oldAuthData.getHost()); + myGithubLoginPanel.setAuthType(oldAuthData.getAuthType()); + GithubAuthData.BasicAuth basicAuth = oldAuthData.getBasicAuth(); + if (basicAuth != null) { + myGithubLoginPanel.setLogin(basicAuth.getLogin()); + } + mySettings = GithubSettings.getInstance(); if (mySettings.isSavePasswordMakesSense()) { myGithubLoginPanel.setSavePasswordSelected(mySettings.isSavePassword()); } @@ -71,17 +78,18 @@ public class GithubLoginDialog extends DialogWrapper { @Override protected void doOKAction() { - final GithubAuthData auth = myGithubLoginPanel.getAuthData(); + final GithubAuthDataHolder authHolder = new GithubAuthDataHolder(myGithubLoginPanel.getAuthData()); try { GithubUtil.computeValueInModal(myProject, "Access to GitHub", new ThrowableConvertor() { @NotNull @Override public GithubUser convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.checkAuthData(auth); + return GithubUtil.checkAuthData(myProject, authHolder, indicator); } }); - saveCredentials(auth); + myAuthData = authHolder.getAuthData(); + if (mySettings.isSavePasswordMakesSense()) { mySettings.setSavePassword(myGithubLoginPanel.isSavePasswordSelected()); } @@ -93,21 +101,19 @@ public class GithubLoginDialog extends DialogWrapper { } } - protected void saveCredentials(GithubAuthData auth) { - final GithubSettings settings = GithubSettings.getInstance(); - settings.setCredentials(myGithubLoginPanel.getHost(), auth, myGithubLoginPanel.isSavePasswordSelected()); + public boolean isSavePasswordSelected() { + return myGithubLoginPanel.isSavePasswordSelected(); + } + + @NotNull + public GithubAuthData getAuthData() { + if (myAuthData == null) { + throw new IllegalStateException("AuthData is not set"); + } + return myAuthData; } public void clearErrors() { setErrorText(null); } - - @NotNull - public GithubAuthData getAuthData() { - return myGithubLoginPanel.getAuthData(); - } - - public void lockHost(String host) { - myGithubLoginPanel.lockHost(host); - } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java index 9e8f9ab300ae..80e5a6fb8d8e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java @@ -100,7 +100,7 @@ public class GithubSettingsPanel { @NotNull @Override public GithubUser convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.checkAuthData(auth); + return GithubUtil.checkAuthData(project, new GithubAuthDataHolder(auth), indicator); } }); @@ -132,13 +132,14 @@ public class GithubSettingsPanel { @NotNull @Override public String convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.runWithValidBasicAuthForHost(project, indicator, getHost(), - new ThrowableConvertor() { - @Override - public String convert(GithubAuthData auth) throws IOException { - return GithubApiUtil.getMasterToken(auth, "IntelliJ plugin"); - } - } + return GithubUtil.runTaskWithBasicAuthForHost(project, GithubAuthDataHolder.createFromSettings(), indicator, getHost(), + new ThrowableConvertor() { + @NotNull + @Override + public String convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getMasterToken(auth, "IntelliJ plugin"); + } + } ); } }) @@ -294,7 +295,7 @@ public class GithubSettingsPanel { public void apply() { if (myCredentialsModified) { - mySettings.setCredentials(getHost(), getAuthData(), true); + mySettings.setAuthData(getAuthData(), true); } mySettings.setConnectionTimeout(getConnectionTimeout()); resetCredentialsModification(); diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java index 63e93a6e230e..f11044422154 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -21,10 +21,12 @@ import org.jetbrains.plugins.github.api.GithubApiUtil; /** * Container for authentication data: - * - host - * - login + * * host + * * credentials * - login/password pair - * or + * or + * - login/password pair/2 factor code + * or * - OAuth2 access token * * @author Aleksey Pivovarov @@ -38,7 +40,6 @@ public class GithubAuthData { @Nullable private final TokenAuth myTokenAuth; private final boolean myUseProxy; - private GithubAuthData(@NotNull AuthType authType, @NotNull String host, @Nullable BasicAuth basicAuth, @@ -51,6 +52,10 @@ public class GithubAuthData { myUseProxy = useProxy; } + public static GithubAuthData createFromSettings() { + return GithubSettings.getInstance().getAuthData(); + } + public static GithubAuthData createAnonymous() { return createAnonymous(GithubApiUtil.DEFAULT_GITHUB_HOST); } @@ -63,6 +68,13 @@ public class GithubAuthData { return new GithubAuthData(AuthType.BASIC, host, new BasicAuth(login, password), null, true); } + public static GithubAuthData createBasicAuthTF(@NotNull String host, + @NotNull String login, + @NotNull String password, + @NotNull String code) { + return new GithubAuthData(AuthType.BASIC, host, new BasicAuth(login, password, code), null, true); + } + public static GithubAuthData createTokenAuth(@NotNull String host, @NotNull String token) { return new GithubAuthData(AuthType.TOKEN, host, null, new TokenAuth(token), true); } @@ -95,13 +107,28 @@ public class GithubAuthData { return myUseProxy; } + @NotNull + public GithubAuthData copyWithTwoFactorCode(@NotNull String code) { + if (myBasicAuth == null) { + throw new IllegalStateException("Two factor authentication can be used only with Login/Password"); + } + + return createBasicAuthTF(getHost(), myBasicAuth.getLogin(), myBasicAuth.getPassword(), code); + } + public static class BasicAuth { @NotNull private final String myLogin; @NotNull private final String myPassword; + @Nullable private final String myCode; private BasicAuth(@NotNull String login, @NotNull String password) { + this(login, password, null); + } + + private BasicAuth(@NotNull String login, @NotNull String password, @Nullable String code) { myLogin = login; myPassword = password; + myCode = code; } @NotNull @@ -113,6 +140,11 @@ public class GithubAuthData { public String getPassword() { return myPassword; } + + @Nullable + public String getCode() { + return myCode; + } } public static class TokenAuth { diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java new file mode 100644 index 000000000000..695dfe734c34 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.github.util; + +import com.intellij.openapi.util.ThrowableComputable; +import org.jetbrains.annotations.NotNull; + + +public class GithubAuthDataHolder { + @NotNull private GithubAuthData myAuthData; + + public GithubAuthDataHolder(@NotNull GithubAuthData auth) { + myAuthData = auth; + } + + @NotNull + public synchronized GithubAuthData getAuthData() { + return myAuthData; + } + + public synchronized void runTransaction(@NotNull GithubAuthData expected, + @NotNull ThrowableComputable task) throws T { + if (expected != myAuthData) { + return; + } + + myAuthData = task.compute(); + } + + public static GithubAuthDataHolder createFromSettings() { + return new GithubAuthDataHolder(GithubSettings.getInstance().getAuthData()); + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java index 49199c0d156b..3523e412a95e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java @@ -59,6 +59,7 @@ public class GithubSettings implements PersistentStateComponent T runTask(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull ThrowableConvertor task) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); + try { + return task.convert(auth); + } + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + return runTask(project, authHolder, indicator, task); + } + catch (GithubAuthenticationException e) { + getValidAuthData(project, authHolder, indicator, auth); + return runTask(project, authHolder, indicator, task); + } + } + + public static void runTask(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull ThrowableConsumer task) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); + try { + task.consume(auth); + } + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + runTask(project, authHolder, indicator, task); + } + catch (GithubAuthenticationException e) { + getValidAuthData(project, authHolder, indicator, auth); + runTask(project, authHolder, indicator, task); + } + } + + @NotNull + public static T runTaskWithBasicAuthForHost(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, @NotNull ProgressIndicator indicator, - @NotNull ThrowableConsumer task) throws IOException { - GithubAuthData auth = GithubSettings.getInstance().getAuthData(); + @NotNull String host, + @NotNull ThrowableConvertor task) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); try { - if (auth.getAuthType() == GithubAuthData.AuthType.ANONYMOUS) { - throw new GithubAuthenticationException("Bad authentication type"); + if (auth.getAuthType() != GithubAuthData.AuthType.BASIC) { + throw new GithubAuthenticationException("Expected basic authentication"); } - task.consume(auth); - return auth; + return task.convert(auth); + } + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + return runTaskWithBasicAuthForHost(project, authHolder, indicator, host, task); } catch (GithubAuthenticationException e) { - auth = getValidAuthData(project, indicator); - task.consume(auth); - return auth; + getValidBasicAuthDataForHost(project, authHolder, indicator, auth, host); + return runTaskWithBasicAuthForHost(project, authHolder, indicator, host, task); } } @NotNull - public static T runWithValidAuth(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull ThrowableConvertor task) throws IOException { - GithubAuthData auth = GithubSettings.getInstance().getAuthData(); + private static GithubUserDetailed testConnection(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); try { - if (auth.getAuthType() == GithubAuthData.AuthType.ANONYMOUS) { - throw new GithubAuthenticationException("Bad authentication type"); - } - return task.convert(auth); + return GithubApiUtil.getCurrentUserDetailed(auth); } - catch (GithubAuthenticationException e) { - auth = getValidAuthData(project, indicator); - return task.convert(auth); + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + return testConnection(project, authHolder, indicator); } } - @NotNull - public static T runWithValidBasicAuthForHost(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull String host, - @NotNull ThrowableConvertor task) throws IOException { - GithubSettings settings = GithubSettings.getInstance(); - GithubAuthData auth = null; - try { - if (settings.getAuthType() != GithubAuthData.AuthType.BASIC || - !StringUtil.equalsIgnoreCase(GithubUrlUtil.getApiUrl(host), GithubUrlUtil.getApiUrl(settings.getHost()))) { - throw new GithubAuthenticationException("Bad authentication type"); - } - auth = settings.getAuthData(); - return task.convert(auth); - } - catch (GithubAuthenticationException e) { - auth = getValidBasicAuthDataForHost(project, indicator, host); - return task.convert(auth); - } - } - - /** - * @return null if user canceled login dialog. Valid GithubAuthData otherwise. - */ - @NotNull - public static GithubAuthData getValidAuthData(@Nullable Project project, @NotNull ProgressIndicator indicator) - throws GithubOperationCanceledException { - final GithubLoginDialog dialog = new GithubLoginDialog(project); - ApplicationManager.getApplication().invokeAndWait(new Runnable() { + public static void getValidAuthData(@NotNull final Project project, + @NotNull final GithubAuthDataHolder authHolder, + @NotNull final ProgressIndicator indicator, + @NotNull final GithubAuthData oldAuth) throws GithubOperationCanceledException { + authHolder.runTransaction(oldAuth, new ThrowableComputable() { @Override - public void run() { - DialogManager.show(dialog); + @NotNull + public GithubAuthData compute() throws GithubOperationCanceledException { + final GithubLoginDialog dialog = new GithubLoginDialog(project, oldAuth); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + DialogManager.show(dialog); + } + }, indicator.getModalityState()); + if (!dialog.isOK()) { + throw new GithubOperationCanceledException("Can't get valid credentials"); + } + GithubAuthData authData = dialog.getAuthData(); + + GithubSettings.getInstance().setAuthData(authData, dialog.isSavePasswordSelected()); + return authData; } - }, indicator.getModalityState()); - if (!dialog.isOK()) { - throw new GithubOperationCanceledException("Can't get valid credentials"); - } - return dialog.getAuthData(); + }); } - /** - * @return null if user canceled login dialog. Valid GithubAuthData otherwise. - */ - @NotNull - public static GithubAuthData getValidBasicAuthDataForHost(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull String host) throws GithubOperationCanceledException { - final GithubLoginDialog dialog = new GithubBasicLoginDialog(project); - dialog.lockHost(host); - ApplicationManager.getApplication().invokeAndWait(new Runnable() { + public static void getValidBasicAuthDataForHost(@NotNull final Project project, + @NotNull final GithubAuthDataHolder authHolder, + @NotNull final ProgressIndicator indicator, + @NotNull final GithubAuthData oldAuth, + @NotNull final String host) throws GithubOperationCanceledException { + authHolder.runTransaction(oldAuth, new ThrowableComputable() { @Override - public void run() { - DialogManager.show(dialog); + @NotNull + public GithubAuthData compute() throws GithubOperationCanceledException { + final GithubLoginDialog dialog = new GithubBasicLoginDialog(project, oldAuth, host); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + DialogManager.show(dialog); + } + }, indicator.getModalityState()); + if (!dialog.isOK()) { + throw new GithubOperationCanceledException("Can't get valid credentials"); + } + GithubAuthData authData = dialog.getAuthData(); + + final GithubSettings settings = GithubSettings.getInstance(); + if (settings.getAuthType() != GithubAuthData.AuthType.TOKEN) { + GithubSettings.getInstance().setAuthData(authData, dialog.isSavePasswordSelected()); + } + return authData; } - }, indicator.getModalityState()); - if (!dialog.isOK()) { - throw new GithubOperationCanceledException("Can't get valid credentials"); - } - return dialog.getAuthData(); + }); + } + + private static void getTwoFactorAuthData(@NotNull final Project project, + @NotNull final GithubAuthDataHolder authHolder, + @NotNull final ProgressIndicator indicator, + @NotNull final GithubAuthData oldAuth) throws GithubOperationCanceledException { + authHolder.runTransaction(oldAuth, new ThrowableComputable() { + @Override + @NotNull + public GithubAuthData compute() throws GithubOperationCanceledException { + if (authHolder.getAuthData().getAuthType() != GithubAuthData.AuthType.BASIC) { + throw new GithubOperationCanceledException("Two factor authentication can be used only with Login/Password"); + } + + GithubApiUtil.askForTwoFactorCodeSMS(oldAuth); + + final Ref codeRef = new Ref(); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + codeRef.set(Messages.showInputDialog(project, "Authentication Code", "Github Two-Factor Authentication", null)); + } + }, indicator.getModalityState()); + if (codeRef.isNull()) { + throw new GithubOperationCanceledException("Can't get two factor authentication code"); + } + + GithubSettings settings = GithubSettings.getInstance(); + if (settings.getAuthType() == GithubAuthData.AuthType.BASIC && + StringUtil.equalsIgnoreCase(settings.getLogin(), oldAuth.getBasicAuth().getLogin())) { + settings.setValidGitAuth(false); + } + + return oldAuth.copyWithTwoFactorCode(codeRef.get()); + } + }); } @NotNull - public static GithubAuthData getValidAuthDataFromConfig(@Nullable Project project, @NotNull ProgressIndicator indicator) + public static GithubAuthDataHolder getValidAuthDataHolderFromConfig(@NotNull Project project, @NotNull ProgressIndicator indicator) throws IOException { - GithubAuthData auth = GithubSettings.getInstance().getAuthData(); + GithubAuthData auth = GithubAuthData.createFromSettings(); + GithubAuthDataHolder authHolder = new GithubAuthDataHolder(auth); try { - checkAuthData(auth); - return auth; + checkAuthData(project, authHolder, indicator); + return authHolder; } catch (GithubAuthenticationException e) { - return getValidAuthData(project, indicator); + getValidAuthData(project, authHolder, indicator, auth); + return authHolder; } } @NotNull - public static GithubUserDetailed checkAuthData(@NotNull GithubAuthData auth) throws IOException { + public static GithubUserDetailed checkAuthData(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); + if (StringUtil.isEmptyOrSpaces(auth.getHost())) { throw new GithubAuthenticationException("Target host not defined"); } @@ -201,37 +279,31 @@ public class GithubUtil { throw new GithubAuthenticationException("Anonymous connection not allowed"); } - return testConnection(auth); + return testConnection(project, authHolder, indicator); } - @NotNull - private static GithubUserDetailed testConnection(@NotNull GithubAuthData auth) throws IOException { - return GithubApiUtil.getCurrentUserDetailed(auth); - } - - public static T computeValueInModal(@NotNull Project project, - @NotNull String caption, - @NotNull final ThrowableConvertor task) throws E { - final AtomicReference dataRef = new AtomicReference(); - final AtomicReference exceptionRef = new AtomicReference(); + public static T computeValueInModal(@NotNull Project project, + @NotNull String caption, + @NotNull final ThrowableConvertor task) throws IOException { + final Ref dataRef = new Ref(); + final Ref exceptionRef = new Ref(); ProgressManager.getInstance().run(new Task.Modal(project, caption, true) { public void run(@NotNull ProgressIndicator indicator) { try { dataRef.set(task.convert(indicator)); } + catch (IOException e) { + exceptionRef.set(e); + } catch (Error e) { - throw e; + exceptionRef.set(new GithubOperationCanceledException(e)); } catch (RuntimeException e) { - throw e; - } - catch (Throwable e) { - //noinspection unchecked - exceptionRef.set((E)e); + exceptionRef.set(new GithubOperationCanceledException(e)); } } }); - if (exceptionRef.get() != null) { + if (!exceptionRef.isNull()) { throw exceptionRef.get(); } return dataRef.get(); @@ -240,7 +312,7 @@ public class GithubUtil { public static T computeValueInModal(@NotNull Project project, @NotNull String caption, @NotNull final Convertor task) { - final AtomicReference dataRef = new AtomicReference(); + final Ref dataRef = new Ref(); ProgressManager.getInstance().run(new Task.Modal(project, caption, true) { public void run(@NotNull ProgressIndicator indicator) { dataRef.set(task.convert(indicator)); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java index 0d394d58f09d..f7ae343204f2 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java @@ -15,8 +15,11 @@ */ package org.jetbrains.plugins.github; +import com.intellij.mock.MockProgressIndicator; import com.intellij.notification.NotificationType; +import com.intellij.openapi.progress.ProgressIndicator; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import java.util.Collections; import java.util.List; @@ -27,10 +30,12 @@ import static org.jetbrains.plugins.github.api.GithubGist.FileContent; * @author Aleksey Pivovarov */ public class GithubCreateGistTest extends GithubCreateGistTestBase { + private final ProgressIndicator myIndicator = new MockProgressIndicator(); + public void testSimple() throws Throwable { List expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, true, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -44,7 +49,9 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testAnonymous() throws Throwable { List expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, GithubAuthData.createAnonymous(myHost), expected, true, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction + .createGist(myProject, new GithubAuthDataHolder(GithubAuthData.createAnonymous(myHost)), myIndicator, expected, true, + GIST_DESCRIPTION, null); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -62,7 +69,8 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testUnusedFilenameField() throws Throwable { List expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, true, GIST_DESCRIPTION, "filename"); + String url = + GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, true, GIST_DESCRIPTION, "filename"); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -77,7 +85,8 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { List content = Collections.singletonList(new FileContent("file.txt", "file.txt content")); List expected = Collections.singletonList(new FileContent("filename", "file.txt content")); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), content, true, GIST_DESCRIPTION, "filename"); + String url = + GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, content, true, GIST_DESCRIPTION, "filename"); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -91,7 +100,7 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testPublic() throws Throwable { List expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, false, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, false, GIST_DESCRIPTION, null); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -105,33 +114,35 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testEmpty() throws Throwable { List expected = Collections.emptyList(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, true, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNull("Gist was created", url); checkNotification(NotificationType.WARNING, "Can't create Gist", "Can't create empty gist"); } public void testWrongLogin() throws Throwable { - registerDefaultLoginDialogHandler(); + registerCancelingLoginDialogHandler(); List expected = createContent(); GithubAuthData auth = myGitHubSettings.getAuthData(); GithubAuthData myAuth = GithubAuthData.createBasicAuth(auth.getHost(), myLogin1 + "some_suffix", myPassword); - String url = GithubCreateGistAction.createGist(myProject, myAuth, expected, true, GIST_DESCRIPTION, null); + String url = + GithubCreateGistAction.createGist(myProject, new GithubAuthDataHolder(myAuth), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNull("Gist was created", url); checkNotification(NotificationType.ERROR, "Can't create Gist", null); } public void testWrongPassword() throws Throwable { - registerDefaultLoginDialogHandler(); + registerCancelingLoginDialogHandler(); List expected = createContent(); GithubAuthData auth = myGitHubSettings.getAuthData(); GithubAuthData myAuth = GithubAuthData.createBasicAuth(auth.getHost(), myLogin1, myPassword + "some_suffix"); - String url = GithubCreateGistAction.createGist(myProject, myAuth, expected, true, GIST_DESCRIPTION, null); + String url = + GithubCreateGistAction.createGist(myProject, new GithubAuthDataHolder(myAuth), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNull("Gist was created", url); checkNotification(NotificationType.ERROR, "Can't create Gist", null); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java index 5e785fa7de44..17a0c68781e4 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java @@ -25,6 +25,7 @@ import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.GithubGist; import org.jetbrains.plugins.github.test.GithubTest; import org.jetbrains.plugins.github.ui.GithubLoginDialog; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import java.io.IOException; import java.util.ArrayList; @@ -51,6 +52,11 @@ public abstract class GithubCreateGistTestBase extends GithubTest { deleteGist(); } + @NotNull + protected GithubAuthDataHolder getAuthDataHolder() { + return new GithubAuthDataHolder(myGitHubSettings.getAuthData()); + } + protected void deleteGist() throws IOException { if (GIST_ID != null) { GithubApiUtil.deleteGist(myGitHubSettings.getAuthData(), GIST_ID); @@ -133,7 +139,7 @@ public abstract class GithubCreateGistTestBase extends GithubTest { assertTrue("Gist content differs from sample", Comparing.haveEqualElements(expected, actual)); } - protected void registerDefaultLoginDialogHandler() { + protected void registerCancelingLoginDialogHandler() { myDialogManager.registerDialogHandler(GithubLoginDialog.class, new TestDialogHandler() { @Override public int handleDialog(GithubLoginDialog dialog) { diff --git a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java index 2c9496e9a27e..1f7635d35601 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java @@ -210,7 +210,7 @@ public abstract class GithubTest extends UsefulTestCase { myAuth = GithubAuthData.createBasicAuth(host, login1, password); myGitHubSettings = GithubSettings.getInstance(); - myGitHubSettings.setCredentials(myHost, myAuth, false); + myGitHubSettings.setAuthData(myAuth, false); myDialogManager = (TestDialogManager)ServiceManager.getService(DialogManager.class); myNotificator = (TestNotificator)ServiceManager.getService(myProject, Notificator.class); diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java index 7e9264ecd1fc..af83972c7ec5 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java @@ -231,7 +231,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { final Process process = Runtime.getRuntime().exec(ArrayUtil.toStringArray(cmd)); final Consumer updater = new Consumer() { public void consume(String s) { - context.processMessage(new ProgressMessage(s + " [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage(s + " [" + chunk.getPresentableShortName() + "]")); } }; final GroovycOSProcessHandler handler = new GroovycOSProcessHandler(process, updater) { diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java index c4b40bfb0956..a03067d99e61 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java @@ -219,10 +219,12 @@ public class GroovycOSProcessHandler extends BaseOSProcessHandler { if (unparsedBuffer.length() != 0) { String msg = unparsedBuffer.toString(); if (msg.contains(GroovyRtConstants.NO_GROOVY)) { - msg = "Cannot compile Groovy files: no Groovy library is defined for module '" + moduleName + "'"; + messages.add(new CompilerMessage("", BuildMessage.Kind.ERROR, + "Cannot compile Groovy files: no Groovy library is defined for module '" + moduleName + "'")); + } else { + messages.add(new CompilerMessage("Groovyc", BuildMessage.Kind.INFO, msg)); } - messages.add(new CompilerMessage("Groovyc", BuildMessage.Kind.INFO, msg)); } final int exitValue = getProcess().exitValue(); diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index f0690246f1c3..68d8b51364b7 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -79,6 +79,7 @@ + @@ -150,7 +151,30 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java index a99f62d9b2c9..4ab96f047175 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -49,7 +49,6 @@ import org.jetbrains.plugins.groovy.refactoring.ui.MethodOrClosureScopeChooser; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Set; /** * @author Max Medvedev @@ -138,9 +137,9 @@ public class CreateParameterFromUsageFix extends Intention implements MethodOrCl if (project.isDisposed()) return; final String name = ref.getReferenceName(); - final Set types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(ref); + final List types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(ref); - PsiType unboxed = types.isEmpty() ? null : TypesUtil.unboxPrimitiveTypeWrapper(types.iterator().next()); + PsiType unboxed = types.isEmpty() ? null : TypesUtil.unboxPrimitiveTypeWrapper(types.get(0)); @NotNull final PsiType type = unboxed != null ? unboxed : PsiType.getJavaLangObject(ref.getManager(), ref.getResolveScope()); if (method instanceof GrMethod) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties index 3d658f098b0e..c19311d13dec 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties @@ -109,4 +109,6 @@ change.lvalue.type=Change variable ''{0}'' type to ''{1}'' replace.qualified.name.with.import=Replace qualified name with import highlight.assignments.from.void=Highlight assignments from void type comments.count.as.content=Comments count as content -ignore.when.catch.parameter.is.named.ignore.or.ignored=Ignore when catch parameter is named ignore or ignored \ No newline at end of file +ignore.when.catch.parameter.is.named.ignore.or.ignored=Ignore when catch parameter is named ignore or ignored +no.applicable.signature.found=No applicable signature found +expected.type.0=Expected {0} \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 970b39123c7c..b0d47a0552b3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -24,6 +24,7 @@ import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; @@ -70,8 +71,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; @@ -79,6 +82,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer; +import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParamsEnhancer; import org.jetbrains.plugins.groovy.lang.psi.util.*; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; @@ -242,7 +246,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitReturnStatement(GrReturnStatement returnStatement) { - super.visitReturnStatement(returnStatement); final GrExpression value = returnStatement.getReturnValue(); if (value == null || isNewInstanceInitialingByTuple(value)) return; @@ -254,7 +257,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitExpression(GrExpression expression) { - super.visitExpression(expression); if (PsiUtil.isExpressionStatement(expression)) { final PsiType returnType = PsiImplUtil.inferReturnType(expression); final GrControlFlowOwner flowOwner = ControlFlowUtils.findControlFlowOwner(expression); @@ -274,8 +276,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitAssignmentExpression(GrAssignmentExpression assignment) { - super.visitAssignmentExpression(assignment); - GrExpression lValue = assignment.getLValue(); if (lValue instanceof GrIndexProperty) return; if (!PsiUtil.mightBeLValue(lValue)) return; @@ -363,8 +363,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitVariable(GrVariable variable) { - super.visitVariable(variable); - PsiType varType = variable.getType(); PsiElement parent = variable.getParent(); @@ -430,7 +428,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitNewExpression(GrNewExpression newExpression) { - super.visitNewExpression(newExpression); if (newExpression.getArrayCount() > 0) return; GrCodeReferenceElement refElement = newExpression.getReferenceElement(); @@ -502,7 +499,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitListOrMap(GrListOrMap listOrMap) { - super.visitListOrMap(listOrMap); final PsiReference reference = listOrMap.getReference(); if (!(reference instanceof LiteralConstructorReference)) return; @@ -515,7 +511,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitThrowStatement(GrThrowStatement throwStatement) { - super.visitThrowStatement(throwStatement); final GrExpression exception = throwStatement.getException(); if (exception != null) { @@ -557,7 +552,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitConstructorInvocation(GrConstructorInvocation invocation) { - super.visitConstructorInvocation(invocation); GrConstructorInvocationInfo info = new GrConstructorInvocationInfo(invocation); checkConstructorCall(info); checkNamedArgumentsType(info); @@ -565,8 +559,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitIndexProperty(GrIndexProperty expression) { - super.visitIndexProperty(expression); - checkIndexProperty(new GrIndexPropertyInfo(expression)); } @@ -651,25 +643,21 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitMethodCallExpression(GrMethodCallExpression methodCallExpression) { - super.visitMethodCallExpression(methodCallExpression); checkMethodCall(new GrMethodCallInfo(methodCallExpression)); } @Override public void visitApplicationStatement(GrApplicationStatement applicationStatement) { - super.visitApplicationStatement(applicationStatement); checkMethodCall(new GrMethodCallInfo(applicationStatement)); } @Override public void visitBinaryExpression(GrBinaryExpression binary) { - super.visitBinaryExpression(binary); checkOperator(new GrBinaryExprInfo(binary)); } @Override public void visitEnumConstant(GrEnumConstant enumConstant) { - super.visitEnumConstant(enumConstant); GrEnumConstantInfo info = new GrEnumConstantInfo(enumConstant); checkConstructorCall(info); checkNamedArgumentsType(info); @@ -710,6 +698,60 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { } } + @Override + public void visitParameterList(final GrParameterList parameterList) { + PsiElement parent = parameterList.getParent(); + if (parent instanceof GrClosableBlock) { + + GrParameter[] parameters = parameterList.getParameters(); + if (parameters.length > 0) { + List signatures = ClosureParamsEnhancer.findFittingSignatures((GrClosableBlock)parent); + final List paramTypes = ContainerUtil.map(parameters, new Function() { + @Override + public PsiType fun(GrParameter parameter) { + return parameter.getType(); + } + }); + + if (signatures.size() > 1) { + PsiType[] fittingSignature = ContainerUtil.find(signatures, new Condition() { + @Override + public boolean value(PsiType[] types) { + for (int i = 0; i < types.length; i++) { + if (!typesAreEqual(types[i], paramTypes.get(i), parameterList)) { + return false; + } + } + return true; + } + }); + + if (fittingSignature == null) { + registerError(parameterList, GroovyInspectionBundle.message("no.applicable.signature.found")); + } + } + else if (signatures.size() == 1) { + PsiType[] types = signatures.get(0); + for (int i = 0; i < types.length; i++) { + GrTypeElement typeElement = parameters[i].getTypeElementGroovy(); + if (typeElement == null) continue; + PsiType expected = types[i]; + PsiType actual = paramTypes.get(i); + if (!typesAreEqual(expected, actual, parameterList)) { + registerError(typeElement, GroovyInspectionBundle.message("expected.type.0", expected.getPresentableText())); + } + } + } + } + } + } + + private static boolean typesAreEqual(@NotNull PsiType expected, @NotNull PsiType actual, @NotNull PsiElement context) { + return TypesUtil.isAssignableByMethodCallConversion(expected, actual, context) && + TypesUtil.isAssignableByMethodCallConversion(actual, expected, context); + } + + /** * checks only children of e */ @@ -1020,6 +1062,11 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { private void highlightUnknownArgs(@NotNull CallInfo info) { registerError(info.getElementToHighlight(), GroovyBundle.message("cannot.infer.argument.types"), LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.WEAK_WARNING); } + + @Override + public void visitElement(GroovyPsiElement element) { + //do nothing + } } @Nullable @@ -1108,12 +1155,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { Object... args) { registerError(location, (String)args[0], LocalQuickFix.EMPTY_ARRAY, highlightType); } - - - @Override - public void visitElement(GroovyPsiElement element) { - //do nothing - } } private static final ThreadLocal visitor = new ThreadLocal() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java index 31a97407fd13..78e3886b7842 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -49,7 +49,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; /** * @author ven @@ -125,9 +124,7 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool { } } else { - final Set expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); - - for (PsiType expectedType : expectedTypes) { + for (PsiType expectedType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure)) { if (TypesUtil.isPsiClassTypeToClosure(expectedType)) { PsiType[] parameters = ((PsiClassType)expectedType).getParameters(); if (parameters.length == 1) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java index 8f9958b2a024..5470ed0490d9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -129,6 +129,8 @@ public class CustomMembersGenerator extends GroovyObjectSupport implements GdslM Methods to add new behavior *********************************************************** */ public void property(Map args) { + if (args == null) return; + String name = (String)args.get("name"); Object type = args.get("type"); Object doc = args.get("doc"); @@ -156,6 +158,8 @@ public class CustomMembersGenerator extends GroovyObjectSupport implements GdslM } public void constructor(Map args) { + if (args == null) return; + args.put("constructor", true); method(args); } @@ -190,8 +194,7 @@ public class CustomMembersGenerator extends GroovyObjectSupport implements GdslM ContainerUtil.map(argTypes, new Function() { @Override public Object fun(PsiType type) { - String canonical = type.getCanonicalText(); - return canonical != null ? canonical : type.getPresentableText(); + return type.getCanonicalText(); } }, types); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index 82cfe11991df..3322dc9e7527 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -131,11 +131,13 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { return myDataIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new MyInputFilter(); @@ -513,7 +515,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return "gdsl".equals(file.getExtension()); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java index 4d1f239101b6..c9f6f98c3132 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java @@ -287,8 +287,7 @@ public class GroovySmartCompletionContributor extends CompletionContributor { placeToInferType = (GrExpression)expression.getParent(); } - final Set types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(placeToInferType); - for (PsiType type : types) { + for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(placeToInferType)) { if (type instanceof PsiArrayType) { final PsiType _type = GenericsUtil.eliminateWildcards(type); final LookupItem item = PsiTypeLookupItem.createLookupItem(_type, place, PsiTypeLookupItem.isDiamond(_type), ChooseTypeExpression.IMPORT_FIXER); @@ -307,7 +306,7 @@ public class GroovySmartCompletionContributor extends CompletionContributor { final List expectedClassTypes = new SmartList(); - for (PsiType psiType : types) { + for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(placeToInferType)) { if (psiType instanceof PsiClassType) { PsiType type = GenericsUtil.eliminateWildcards(JavaCompletionUtil.originalize(psiType)); final PsiClassType classType = (PsiClassType)type; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index 09ce7cc83ea9..1d541a0b83c2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -22,6 +22,7 @@ import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,14 +53,15 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; @@ -97,12 +99,14 @@ public class GroovyExpectedTypesProvider { }); } - public static Set getDefaultExpectedTypes(@NotNull GrExpression element) { - final LinkedHashSet result = new LinkedHashSet(); - for (TypeConstraint constraint : calculateTypeConstraints(element)) { - result.add(constraint.getDefaultType()); - } - return result; + public static List getDefaultExpectedTypes(@NotNull GrExpression element) { + TypeConstraint[] constraints = calculateTypeConstraints(element); + return ContainerUtil.map(constraints, new Function() { + @Override + public PsiType fun(TypeConstraint constraint) { + return constraint.getDefaultType(); + } + }); } private static class MyCalculator extends GroovyElementVisitor { @@ -176,8 +180,8 @@ public class GroovyExpectedTypesProvider { final GrClosableBlock[] closureArgs = methodCall.getClosureArguments(); if (ArrayUtil.contains(myExpression, closureArgs)) { final GrArgumentList argumentList = methodCall.getArgumentList(); - final GrNamedArgument[] namedArgs = argumentList == null ? GrNamedArgument.EMPTY_ARRAY : argumentList.getNamedArguments(); - final GrExpression[] expressionArgs = argumentList == null ? GrExpression.EMPTY_ARRAY : argumentList.getExpressionArguments(); + final GrNamedArgument[] namedArgs = argumentList.getNamedArguments(); + final GrExpression[] expressionArgs = argumentList.getExpressionArguments(); final GroovyResolveResult[] callVariants = ResolveUtil.getCallVariants(myExpression); processCallVariants(methodCall, callVariants, namedArgs, expressionArgs, closureArgs); } @@ -344,18 +348,32 @@ public class GroovyExpectedTypesProvider { @NotNull GrNamedArgument[] namedArguments, @NotNull GrExpression[] expressionArguments, @NotNull GrClosableBlock[] closureArguments) { + + List> expectedParams = + ResolveUtil.collectExpectedParamsByArg(place, variants, namedArguments, expressionArguments, closureArguments, myExpression); + + collectExpectedTypeFromPossibleParams(expectedParams); + } + + private void collectExpectedTypeFromPossibleParams(List> expectedParams) { List constraints = ContainerUtil.newArrayList(); - for (GroovyResolveResult variant : variants) { - final Map> map = GrClosureSignatureUtil.mapArgumentsToParameters( - variant, place, true, true, namedArguments, expressionArguments, closureArguments - ); - addConstraintsFromMap(constraints, map); + for (Pair pair : expectedParams) { + final PsiType type = pair.second; + if (type != null) { + + constraints.add(SubtypeConstraint.create(type)); + + if (type instanceof PsiArrayType && pair.first.isVarArgs()) { + constraints.add(SubtypeConstraint.create(((PsiArrayType)type).getComponentType())); + } + } } if (!constraints.isEmpty()) { myResult = constraints.toArray(new TypeConstraint[constraints.size()]); } } + @Override public void visitBinaryExpression(GrBinaryExpression expression) { final IElementType type = expression.getOperationTokenType(); @@ -382,7 +400,8 @@ public class GroovyExpectedTypesProvider { } } else { //myExpression == right - processCallVariants(expression, callVariants, GrNamedArgument.EMPTY_ARRAY, new GrExpression[]{myExpression}, GrClosableBlock.EMPTY_ARRAY); + processCallVariants(expression, callVariants, GrNamedArgument.EMPTY_ARRAY, new GrExpression[]{myExpression}, + GrClosableBlock.EMPTY_ARRAY); } } @@ -398,22 +417,6 @@ public class GroovyExpectedTypesProvider { } } - private void addConstraintsFromMap(List constraints, Map> map) { - if (map == null) return; - - final Pair pair = map.get(myExpression); - if (pair == null) return; - - final PsiType type = pair.second; - if (type == null) return; - - constraints.add(SubtypeConstraint.create(type)); - - if (type instanceof PsiArrayType && pair.first.isVarArgs()) { - constraints.add(SubtypeConstraint.create(((PsiArrayType)type).getComponentType())); - } - } - public void visitAssignmentExpression(GrAssignmentExpression expression) { GrExpression rValue = expression.getRValue(); GrExpression lValue = expression.getLValue(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java index 387db8400b1e..b43ee28c1ece 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -15,11 +15,11 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl; -import com.intellij.psi.PsiAnnotation; -import com.intellij.psi.PsiAnnotationMemberValue; -import com.intellij.psi.PsiLiteral; +import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; /** * @author Max Medvedev @@ -54,4 +54,52 @@ public class GrAnnotationUtil { } return null; } + + @Nullable + public static PsiClass inferClassAttribute(@NotNull PsiAnnotation annotation, @NotNull String attributeName) { + final PsiAnnotationMemberValue targetValue = annotation.findAttributeValue(attributeName); + if (targetValue instanceof PsiClassObjectAccessExpression) { + PsiType type = ((PsiClassObjectAccessExpression)targetValue).getOperand().getType(); + if (type instanceof PsiClassType) { + return ((PsiClassType)type).resolve(); + } + } + else if (targetValue instanceof GrReferenceExpression) { + if ("class".equals(((GrReferenceExpression)targetValue).getReferenceName())) { + GrExpression qualifier = ((GrReferenceExpression)targetValue).getQualifier(); + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiClass) { + return (PsiClass)resolved; + } + } + } + PsiElement resolved = ((GrReferenceExpression)targetValue).resolve(); + if (resolved instanceof PsiClass) return (PsiClass)resolved; + } + return null; + } + + @Nullable + public static PsiType extractClassTypeFromClassAttributeValue(PsiAnnotationMemberValue targetValue) { + if (targetValue instanceof PsiClassObjectAccessExpression) { + return ((PsiClassObjectAccessExpression)targetValue).getOperand().getType(); + } + else if (targetValue instanceof GrReferenceExpression) { + if ("class".equals(((GrReferenceExpression)targetValue).getReferenceName())) { + GrExpression qualifier = ((GrReferenceExpression)targetValue).getQualifier(); + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiClass) { + return qualifier.getType(); + } + } + } + PsiElement resolved = ((GrReferenceExpression)targetValue).resolve(); + if (resolved instanceof PsiClass) { + return ((GrReferenceExpression)targetValue).getType(); + } + } + return null; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 3119608176ff..825f4d86fdd7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -484,10 +484,11 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl expectedTypes; + List expectedTypes; if (closure.getParent() instanceof GrSafeCastExpression) { GrSafeCastExpression safeCastExpression = (GrSafeCastExpression)closure.getParent(); GrTypeElement typeElement = safeCastExpression.getCastTypeElement(); if (typeElement != null) { PsiType castType = typeElement.getType(); - expectedTypes = ContainerUtil.newHashSet(GroovyExpectedTypesProvider.getDefaultExpectedTypes(safeCastExpression)); + expectedTypes = ContainerUtil.newArrayList(GroovyExpectedTypesProvider.getDefaultExpectedTypes(safeCastExpression)); for (Iterator iterator = expectedTypes.iterator(); iterator.hasNext(); ) { if (!TypesUtil.isAssignable(iterator.next(), castType, closure)) { iterator.remove(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java index 2e88f33faa8d..3bea053115a0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java @@ -16,11 +16,9 @@ package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.hash.HashMap; import com.intellij.util.containers.hash.HashSet; @@ -37,7 +35,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGd import org.jetbrains.plugins.groovy.lang.psi.impl.GrRangeType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -133,17 +130,10 @@ public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer { return null; } - PsiType fromSam = inferParameterTypeFromSAM((GrMethodCall)parent, closure, index); - if (fromSam != null) { - return fromSam; - } - String methodName = findMethodName((GrMethodCall)parent); GrExpression expression = ((GrMethodCall)parent).getInvokedExpression(); if (!(expression instanceof GrReferenceExpression)) return null; -// final PsiElement resolved = ((GrReferenceExpression)expression).resolve(); -// if (!(resolved instanceof GrGdkMethod)) return null; GrExpression qualifier = ((GrReferenceExpression)expression).getQualifierExpression(); if (qualifier == null) return null; @@ -264,42 +254,6 @@ public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer { return null; } - @Nullable - private static PsiType inferParameterTypeFromSAM(@NotNull GrMethodCall methodCall, @NotNull GrClosableBlock closure, int index) { - if (!ClosureToSamConverter.isSamConversionAllowed(methodCall)) return null; - - GroovyResolveResult resolveResult = methodCall.advancedResolve(); - PsiElement resolved = resolveResult.getElement(); - - if (!(resolved instanceof PsiMethod)) return null; - - - - Map> map = GrClosureSignatureUtil.mapArgumentsToParameters(resolveResult, methodCall, false, true, - methodCall.getNamedArguments(), - methodCall.getExpressionArguments(), - methodCall.getClosureArguments()); - if (map == null) return null; - - Pair samParameter = map.get(closure); - assert samParameter != null; - - PsiType samTypeSubstituted = samParameter.getSecond(); - if (!(samTypeSubstituted instanceof PsiClassType)) return null; - - MethodSignature samSignature = ClosureToSamConverter.findSAMSignature(samTypeSubstituted); - if (samSignature == null) return null; - - PsiType[] parameterTypes = samSignature.getParameterTypes(); - - if (index >= parameterTypes.length) { - return null; - } - - return parameterTypes[index]; - } - - @Nullable private static PsiType getEntryForMap(@Nullable PsiType map, @NotNull final Project project, @NotNull final GlobalSearchScope scope) { PsiType key = PsiUtil.substituteTypeParameter(map, CommonClassNames.JAVA_UTIL_MAP, 0, true); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParamsEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParamsEnhancer.java new file mode 100644 index 000000000000..d71763079839 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParamsEnhancer.java @@ -0,0 +1,144 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 27/02/14 + */ +public class ClosureParamsEnhancer extends AbstractClosureParameterEnhancer { + + @Nullable + @Override + protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { + if (!GroovyConfigUtils.getInstance().isVersionAtLeast(closure, GroovyConfigUtils.GROOVY2_3)) return null; + + final GrParameter[] parameters = closure.getAllParameters(); + if (containsParametersWithDeclaredType(parameters)) { + return null; + } + + List fittingSignatures = findFittingSignatures(closure); + + if (fittingSignatures.size() == 1) { + PsiType[] expectedSignature = fittingSignatures.get(0); + return expectedSignature[index]; + } + + return null; + } + + @NotNull + public static List findFittingSignatures(GrClosableBlock closure) { + + final GrParameter[] parameters = closure.getAllParameters(); + + GrCall call = findCall(closure); + if (call == null) return Collections.emptyList(); + + GroovyResolveResult resolveResult = call.advancedResolve(); + PsiElement element = resolveResult.getElement(); + + if (!(element instanceof PsiMethod)) { + return Collections.emptyList(); + } + + while (element instanceof PsiMirrorElement) { + element = ((PsiMirrorElement)element).getPrototype(); + } + + List> params = ResolveUtil.collectExpectedParamsByArg(closure, + new GroovyResolveResult[]{resolveResult}, + call.getNamedArguments(), + call.getExpressionArguments(), + call.getClosureArguments(), closure); + if (params.isEmpty()) return Collections.emptyList(); + + Pair pair = params.get(0); + + PsiParameter param = pair.getFirst(); + PsiModifierList modifierList = param.getModifierList(); + if (modifierList == null) return Collections.emptyList(); + + PsiAnnotation anno = modifierList.findAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_STC_CLOSURE_PARAMS); + if (anno == null) return Collections.emptyList(); + + PsiClass closureSignatureHint = GrAnnotationUtil.inferClassAttribute(anno, "value"); + if (closureSignatureHint == null) return Collections.emptyList(); + + String qnameOfClosureSignatureHint = closureSignatureHint.getQualifiedName(); + if (qnameOfClosureSignatureHint == null) return Collections.emptyList(); + + SignatureHintProcessor signatureHintProcessor = SignatureHintProcessor.getHintProcessor(qnameOfClosureSignatureHint); + if (signatureHintProcessor == null) return Collections.emptyList(); + + List expectedSignatures = signatureHintProcessor.inferExpectedSignatures((PsiMethod)element, + resolveResult.getSubstitutor(), + SignatureHintProcessor.buildOptions(anno)); + + return ContainerUtil.findAll(expectedSignatures, new Condition() { + @Override + public boolean value(PsiType[] types) { + return types.length == parameters.length; + } + }); + } + + private static boolean containsParametersWithDeclaredType(GrParameter[] parameters) { + return ContainerUtil.find(parameters, new Condition() { + @Override + public boolean value(GrParameter parameter) { + return parameter.getDeclaredType() != null; + } + }) != null; + } + + @Nullable + private static GrCall findCall(@NotNull GrClosableBlock closure) { + PsiElement parent = closure.getParent(); + if (parent instanceof GrCall && ArrayUtil.contains(closure, ((GrCall)parent).getClosureArguments())) { + return (GrCall)parent; + } + + if (parent instanceof GrArgumentList) { + PsiElement pparent = parent.getParent(); + if (pparent instanceof GrCall) { + return (GrCall)pparent; + } + } + + return null; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FirstParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FirstParamHintProcessor.java new file mode 100644 index 000000000000..7fdc10341c41 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FirstParamHintProcessor.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class FirstParamHintProcessor extends ParamHintProcessor { + public FirstParamHintProcessor() { + super("groovy.transform.stc.FirstParam", 0, -1); + } + + public static class FirstGeneric extends ParamHintProcessor { + public FirstGeneric() { + super("groovy.transform.stc.FirstParam.FirstGenericType", 0, 0); + } + } + + public static class SecondGeneric extends ParamHintProcessor { + public SecondGeneric() { + super("groovy.transform.stc.FirstParam.SecondGenericType", 0, 1); + } + } + + public static class ThirdGeneric extends ParamHintProcessor { + public ThirdGeneric() { + super("groovy.transform.stc.FirstParam.ThirdGenericType", 0, 2); + } + } + + public static class Component extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.FirstParam.Component"; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + List signatures = new FirstParamHintProcessor().inferExpectedSignatures(method, substitutor, options); + if (signatures.size() == 1) { + PsiType[] signature = signatures.get(0); + if (signature.length == 1) { + PsiType type = signature[0]; + if (type instanceof PsiArrayType) { + return produceResult(((PsiArrayType)type).getComponentType()); + } + } + } + return Collections.emptyList(); + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsHintProcessor.java new file mode 100644 index 000000000000..d1c666fda47b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsHintProcessor.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.codeInsight.generation.OverrideImplementExploreUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignature; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class FromAbstractTypeMethodsHintProcessor extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.FromAbstractTypeMethods"; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + if (options.length != 1) return Collections.emptyList(); + + String qname = options[0]; + PsiClass aClass = JavaPsiFacade.getInstance(method.getProject()).findClass(qname, method.getResolveScope()); + if (aClass == null) return Collections.emptyList(); + + Collection abstractSignatures = OverrideImplementExploreUtil.getMethodSignaturesToImplement(aClass); + return ContainerUtil.map(abstractSignatures, new Function() { + @Override + public PsiType[] fun(MethodSignature signature) { + return signature.getParameterTypes(); + } + }); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java new file mode 100644 index 000000000000..6ca36c5bb70f --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class FromStringHintProcessor extends SignatureHintProcessor { + + @Override + public String getHintName() { + return "groovy.transform.stc.FromString"; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull final PsiMethod method, + @NotNull final PsiSubstitutor substitutor, + @NotNull String[] options) { + return ContainerUtil.map(options, new Function() { + @Override + public PsiType[] fun(String value) { + String[] params = value.split(","); + return ContainerUtil.map(params, new Function() { + @Override + public PsiType fun(String param) { + try { + PsiType original = JavaPsiFacade.getElementFactory(method.getProject()).createTypeFromText(param, method); + return substitutor.substitute(original); + } + catch (IncorrectOperationException e) { + //do nothing. Just don't throw an exception + } + return PsiType.NULL; + } + }, new PsiType[params.length]); + } + }); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/MapEntryOrKeyValueHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/MapEntryOrKeyValueHintProcessor.java new file mode 100644 index 000000000000..799d02a50dd0 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/MapEntryOrKeyValueHintProcessor.java @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtilRt; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class MapEntryOrKeyValueHintProcessor extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.MapEntryOrKeyValue"; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + int argNum = extractArgNum(options); + boolean index = extractIndex(options); + + PsiParameter[] parameters = method.getParameterList().getParameters(); + + if (argNum >= parameters.length) return ContainerUtil.emptyList(); + + PsiParameter parameter = parameters[argNum]; + PsiType type = parameter.getType(); + PsiType substituted = substitutor.substitute(type); + + if (!InheritanceUtil.isInheritor(substituted, CommonClassNames.JAVA_UTIL_MAP)) return ContainerUtil.emptyList(); + + PsiType key = PsiUtil.substituteTypeParameter(substituted, CommonClassNames.JAVA_UTIL_MAP, 0, true); + PsiType value = PsiUtil.substituteTypeParameter(substituted, CommonClassNames.JAVA_UTIL_MAP, 1, true); + + PsiClass mapEntry = JavaPsiFacade.getInstance(method.getProject()).findClass(CommonClassNames.JAVA_UTIL_MAP_ENTRY, method.getResolveScope()); + if (mapEntry == null) return ContainerUtil.emptyList(); + + PsiClassType mapEntryType = JavaPsiFacade.getElementFactory(method.getProject()).createType(mapEntry, key, value); + + PsiType[] keyValueSignature = index ? new PsiType[]{key, value, PsiType.INT} : new PsiType[]{key, value}; + PsiType[] mapEntrySignature = index ? new PsiType[]{mapEntryType, PsiType.INT} : new PsiType[]{mapEntryType}; + + return ContainerUtil.newArrayList(keyValueSignature, mapEntrySignature); + } + + private static int extractArgNum(String[] options) { + + + for (String value : options) { + Integer parsedValue = parseArgNum(value); + if (parsedValue != null) { + return parsedValue; + } + } + + if (options.length == 1) { + return StringUtilRt.parseInt(options[0], 0); + } + + return 0; + } + + private static boolean extractIndex(String[] options) { + for (String value : options) { + Boolean parsedValue = parseIndex(value); + if (parsedValue != null) { + return parsedValue; + } + } + + if (options.length == 1) { + return StringUtilRt.parseBoolean(options[0], false); + } + + return false; + } + + private static Boolean parseIndex(String value) { + Pair pair = parseValue(value); + if (pair == null) return null; + + Boolean parsedValue = StringUtilRt.parseBoolean(pair.getSecond(), false); + if ("index".equals(pair.getFirst())) { + return parsedValue; + } + + return null; + } + + private static Integer parseArgNum(String value) { + Pair pair = parseValue(value); + if (pair == null) return null; + + Integer parsedValue = StringUtilRt.parseInt(pair.getSecond(), 0); + if ("argNum".equals(pair.getFirst())) { + return parsedValue; + } + + return null; + } + + @Nullable + private static Pair parseValue(String value) { + String[] splitted = value.split("="); + + if (splitted.length == 2) { + return Pair.create(splitted[0].trim(), splitted[1].trim()); + } + + return null; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ParamHintProcessor.java new file mode 100644 index 000000000000..3c9ac95506b5 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ParamHintProcessor.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.ContainerUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public abstract class ParamHintProcessor extends SignatureHintProcessor { + private final int myParam; + private final int myGeneric; + private final String myHint; + + public ParamHintProcessor(String hint, int param, int generic) { + myHint = hint; + myParam = param; + myGeneric = generic; + } + + @Override + public String getHintName() { + return myHint; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + PsiParameter[] parameters = method.getParameterList().getParameters(); + if (myParam < parameters.length) { + PsiParameter parameter = parameters[myParam]; + PsiType originalType = parameter.getType(); + + PsiType substituted = substitutor.substitute(originalType); + + if (myGeneric == -1) { + return produceResult(substituted); + } + else { + if (substituted instanceof PsiClassType) { + PsiType[] typeParameters = ((PsiClassType)substituted).getParameters(); + if (myGeneric < typeParameters.length) { + return produceResult(typeParameters[myGeneric]); + } + //if (substituted.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + // return produceResult(TypesUtil.createType(CommonClassNames.JAVA_LANG_CHARACTER, method)); + //} + } + } + } + return ContainerUtilRt.emptyList(); + } + + @NotNull + protected static ArrayList produceResult(@Nullable PsiType type) { + PsiType notNull = type != null ? type : PsiType.NULL; + PsiType[] signature = {notNull}; + ArrayList result = ContainerUtil.newArrayList(); + result.add(signature); + return result; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SecondParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SecondParamHintProcessor.java new file mode 100644 index 000000000000..fbfa821327d2 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SecondParamHintProcessor.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class SecondParamHintProcessor extends ParamHintProcessor { + public SecondParamHintProcessor() { + super("groovy.transform.stc.SecondParam", 1, -1); + } + + public static class FirstGeneric extends ParamHintProcessor { + public FirstGeneric() { + super("groovy.transform.stc.SecondParam.FirstGenericType", 1, 0); + } + } + + public static class SecondGeneric extends ParamHintProcessor { + public SecondGeneric() { + super("groovy.transform.stc.SecondParam.SecondGenericType", 1, 1); + } + } + + public static class ThirdGeneric extends ParamHintProcessor { + public ThirdGeneric() { + super("groovy.transform.stc.SecondParam.ThirdGenericType", 1, 2); + } + } + + public static class Component extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.SecondParam.Component"; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + List signatures = new SecondParamHintProcessor().inferExpectedSignatures(method, substitutor, options); + if (signatures.size() == 1) { + PsiType[] signature = signatures.get(0); + if (signature.length == 1) { + PsiType type = signature[0]; + if (type instanceof PsiArrayType) { + return produceResult(((PsiArrayType)type).getComponentType()); + } + } + } + return Collections.emptyList(); + } + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SignatureHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SignatureHintProcessor.java new file mode 100644 index 000000000000..44c8f2ac5094 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SignatureHintProcessor.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public abstract class SignatureHintProcessor { + private static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.intellij.groovy.signatureHintProcessor"); + + static String[] buildOptions(PsiAnnotation anno) { + PsiAnnotationMemberValue options = anno.findAttributeValue("options"); + if (options instanceof PsiLiteral) { + Object value = ((PsiLiteral)options).getValue(); + if (value instanceof String) { + return new String[]{(String)value}; + } + } + else if (options instanceof PsiArrayInitializerMemberValue) { + PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)options).getInitializers(); + ArrayList result = ContainerUtil.newArrayList(); + for (PsiAnnotationMemberValue initializer : initializers) { + if (initializer instanceof PsiLiteral) { + Object value = ((PsiLiteral)initializer).getValue(); + if (value instanceof String) { + result.add((String)value); + } + } + } + + return ArrayUtil.toStringArray(result); + } + + return ArrayUtil.EMPTY_STRING_ARRAY; + } + + public abstract String getHintName(); + + @NotNull + public abstract List inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options); + + @Nullable + public static SignatureHintProcessor getHintProcessor(@NotNull String hint) { + for (SignatureHintProcessor processor : EP_NAME.getExtensions()) { + if (hint.equals(processor.getHintName())) { + return processor; + } + } + + return null; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SimpleTypeHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SimpleTypeHintProcessor.java new file mode 100644 index 000000000000..dc5fafe40715 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SimpleTypeHintProcessor.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import org.codehaus.groovy.runtime.DefaultGroovyMethods; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class SimpleTypeHintProcessor extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.SimpleType"; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull final PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + return Collections.singletonList(ContainerUtil.map(options, new Function() { + @Override + public PsiType fun(String value) { + try { + PsiType type = JavaPsiFacade.getElementFactory(method.getProject()).createTypeFromText(value, method); + return DefaultGroovyMethods.asBoolean(type) ? type : PsiType.NULL; + } + catch (IncorrectOperationException e) { + return PsiType.NULL; + } + } + }, new PsiType[options.length])); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ThirdParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ThirdParamHintProcessor.java new file mode 100644 index 000000000000..89d935593b1a --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ThirdParamHintProcessor.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class ThirdParamHintProcessor extends ParamHintProcessor { + public ThirdParamHintProcessor() { + super("groovy.transform.stc.ThirdParam", 2, -1); + } + + public static class FirstGeneric extends ParamHintProcessor { + public FirstGeneric() { + super("groovy.transform.stc.ThirdParam.FirstGenericType", 2, 0); + } + } + + public static class SecondGeneric extends ParamHintProcessor { + public SecondGeneric() { + super("groovy.transform.stc.ThirdParam.SecondGenericType", 2, 1); + } + } + + public static class ThirdGeneric extends ParamHintProcessor { + public ThirdGeneric() { + super("groovy.transform.stc.ThirdParam.ThirdGenericType", 2, 2); + } + } + + public static class Component extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.ThirdParam.Component"; + } + + @NotNull + @Override + public List inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + List signatures = new ThirdParamHintProcessor().inferExpectedSignatures(method, substitutor, options); + if (signatures.size() == 1) { + PsiType[] signature = signatures.get(0); + if (signature.length == 1) { + PsiType type = signature[0]; + if (type instanceof PsiArrayType) { + return produceResult(((PsiArrayType)type).getComponentType()); + } + } + } + return Collections.emptyList(); + } + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java index cfd5a265f6c8..0cf18709c585 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -68,7 +68,7 @@ public final class GroovyCommonClassNames { @NonNls public static final String GROOVY_LANG_DELEGATES_TO = "groovy.lang.DelegatesTo"; @NonNls public static final String GROOVY_LANG_DELEGATES_TO_TARGET = "groovy.lang.DelegatesTo.Target"; @NonNls public static final String GROOVY_TRANSFORM_COMPILE_DYNAMIC = "groovy.transform.CompileDynamic"; - + @NonNls public static final String GROOVY_TRANSFORM_STC_CLOSURE_PARAMS = "groovy.transform.stc.ClosureParams"; public static final Set GROOVY_EXTENSION_CLASSES = Collections.unmodifiableSet(ContainerUtil.newLinkedHashSet( "org.codehaus.groovy.runtime.DateGroovyMethods", diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 98bd1d918f5c..ad16d8d71297 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -48,6 +48,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; @@ -916,6 +917,33 @@ public class ResolveUtil { } } + @NotNull + public static List> collectExpectedParamsByArg(@NotNull PsiElement place, + @NotNull GroovyResolveResult[] variants, + @NotNull GrNamedArgument[] namedArguments, + @NotNull GrExpression[] expressionArguments, + @NotNull GrClosableBlock[] closureArguments, + @NotNull GrExpression arg) { + List> expectedParams = ContainerUtil.newArrayList(); + + for (GroovyResolveResult variant : variants) { + final Map> map = GrClosureSignatureUtil.mapArgumentsToParameters( + variant, place, true, true, namedArguments, expressionArguments, closureArguments + ); + + if (map != null) { + final Pair pair = map.get(arg); + ContainerUtil.addIfNotNull(expectedParams, pair); + } + } + return expectedParams; + } + + @NotNull + public static List> collectExpectedParamsByArg(@NotNull GrCall call, @NotNull GrExpression arg) { + return collectExpectedParamsByArg(arg, call.getCallVariants(arg), call.getNamedArguments(), call.getExpressionArguments(), call.getClosureArguments(), arg); + } + private static class DuplicateVariablesProcessor extends PropertyResolverProcessor { private boolean myBorderPassed; private final boolean myHasVisibilityModifier; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java index 10e93acc5a22..e78cc0800d24 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java @@ -730,7 +730,7 @@ public abstract class GrIntroduceHandlerBase T foo(T arg, @ClosureParams(FirstParam) Closure c) { c.call(arg) } + +@CompileStatic +def test() { + assert foo('a') { it.toUpperCase() } == 'A' +} +''' + } + + void testFromStringWithSimpleType() { + assertScript ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') } + +@CompileStatic +def test() { + foo { String str -> println str.toUpperCase()} +} +''' + + shouldFailWithMessages ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') } + +@CompileStatic +def test() { + foo { Date str -> println str} +} +''' + } + + void testFromStringWithGenericType() { + assertScript ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.util.List") Closure cl) { cl.call(['foo']) } + +@CompileStatic +def test() { + foo { List str -> str.each { println it.toUpperCase() } } +} +''' + + shouldFailWithMessages ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.util.List") Closure cl) { cl.call(['foo']) } + +@CompileStatic +def test() { + foo { List d -> d.each { println it } } +} +''' + } + + void testFromStringWithDirectGenericPlaceholder() { + + assertScript ''' +import groovy.transform.stc.FromString + +public void foo(T t, @ClosureParams(value=FromString,options="T") Closure cl) { cl.call(t) } + +@CompileStatic +def test() { + foo('hey') { println it.toUpperCase() } +} +''' + + } + + void testFromStringWithGenericPlaceholder() { + assertScript ''' +import groovy.transform.stc.FromString + +public void foo(T t, @ClosureParams(value=FromString,options="java.util.List") Closure cl) { cl.call([t,t]) } + +@CompileStatic +def test() { + foo('hey') { List str -> str.each { println it.toUpperCase() } } +} +''' + + } + + void testFromStringWithGenericPlaceholderFromClass() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + public void foo(@ClosureParams(value=FromString,options="java.util.List") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo() + + foo.foo { List str -> str.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenerics() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + public void foo(@ClosureParams(value=FromString,options="java.util.List") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo() + + foo.foo { List str -> str.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignature() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + public void foo(@ClosureParams(value=FromString,options="java.util.List") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo() + + foo.foo { it.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQN() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + public void foo(@ClosureParams(value=FromString,options="List") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo() + + foo.foo { it.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClass() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + void bar() { + println 'Haha!' + } +} + +class Tor { + public void foo(@ClosureParams(value=FromString,options="List") Closure cl) { cl.call([new Foo(), new Foo()]) } +} + +@CompileStatic +def test() { + def tor = new Tor() + + tor.foo { it.each { it.bar() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClassAndTwoArgs() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + void bar() { + println 'Haha!' + } +} + +class Tor { + public void foo(@ClosureParams(value=FromString,options=["D,List"]) Closure cl) { cl.call(3, [new Foo(), new Foo()]) } +} + +@CompileStatic +def test() { + + def tor = new Tor() + + tor.foo { r, e -> r.times { e.each { it.bar() } } } +} +''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndPolymorphicSignature() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + void bar() { + println 'Haha!' + } +} + +class Tor { + public void foo(@ClosureParams(value=FromString,options=["D,List", "D"]) Closure cl) { + if (cl.maximumNumberOfParameters==2) { + cl.call(3, [new Foo(), new Foo()]) + } else { + cl.call(3) + } + } +} + +@CompileStatic +def test() { + def tor = new Tor() + + tor.foo { r, e -> r.times { e.each { it.bar() } } } + tor.foo { it.times { println 'polymorphic' } } +} +''' + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy index 54543f271545..97fb5d1345dc 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -15,9 +15,7 @@ */ package org.jetbrains.plugins.groovy.refactoring.optimizeImports - import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase -import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection /** * @author peter */ @@ -27,20 +25,34 @@ public class GroovyAddImportActionTest extends LightCodeInsightFixtureTestCase { myFixture.addClass 'package foo; public class Log {}' myFixture.addClass 'package bar; public class Log {}' myFixture.addClass 'package bar; public class LogFactory { public static Log log(){} }' - myFixture.configureByText 'a.groovy', ''' + doTest('''\ public class Foo { Log l = bar.LogFactory.log(); } -''' - myFixture.enableInspections(new GrUnresolvedAccessInspection()) +''', '''\ +import bar.Log +public class Foo { + Log l = bar.LogFactory.log(); +} +''') + } + + void testReferenceWithErrors() { + myFixture.addClass 'package foo; public class Abc {}' + doTest('''\ +Abc foo = null +''', '''\ +import foo.Abc + +Abc foo = null +''') + } + + private void doTest(String before, String after) { + myFixture.configureByText 'a.groovy', before importClass() - myFixture.checkResult '''import bar.Log - -public class Foo { - Log l = bar.LogFactory.log(); -} -''' + myFixture.checkResult after } private def importClass() { diff --git a/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar b/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar index 3b5173f970df..720d4a962bac 100644 Binary files a/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar and b/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar differ diff --git a/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar b/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar index 10561a4d95e1..e853e975c532 100644 Binary files a/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar and b/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar differ diff --git a/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java b/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java index 6748c0738622..65b15576c6a3 100644 --- a/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java +++ b/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java @@ -5,7 +5,10 @@ import com.oracle.javafx.scenebuilder.kit.editor.panel.content.ContentPanelContr import com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.treeview.HierarchyTreeViewController; import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController; import com.oracle.javafx.scenebuilder.kit.editor.panel.library.LibraryPanelController; -import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; +import com.oracle.javafx.scenebuilder.kit.editor.selection.AbstractSelectionGroup; +import com.oracle.javafx.scenebuilder.kit.editor.selection.ObjectSelectionGroup; +import com.oracle.javafx.scenebuilder.kit.fxom.*; +import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; @@ -17,6 +20,7 @@ import javafx.scene.control.SplitPane; import javax.swing.*; import java.net.URL; +import java.util.*; /** * @author Alexander Lobas @@ -26,8 +30,10 @@ public class SceneBuilderImpl implements SceneBuilder { private final EditorCallback myEditorCallback; private final JFXPanel myPanel = new JFXPanel(); private EditorController myEditorController; - private ChangeListener myListener; private volatile boolean mySkipChanges; + private ChangeListener myListener; + private ChangeListener mySelectionListener; + private final Map mySelectionState = new FixedHashMap(16); public SceneBuilderImpl(URL url, EditorCallback editorCallback) { myFileURL = url; @@ -80,7 +86,6 @@ public class SceneBuilderImpl implements SceneBuilder { Platform.runLater(new Runnable() { @Override public void run() { - // TODO: restore state loadFile(); } }); @@ -96,13 +101,26 @@ public class SceneBuilderImpl implements SceneBuilder { } } }; + mySelectionListener = new ChangeListener() { + @Override + public void changed(ObservableValue observable, Number oldValue, Number newValue) { + if (!mySkipChanges) { + int[][] state = getSelectionState(); + if (state != null) { + mySelectionState.put(myEditorController.getFxmlText(), state); + } + } + } + }; myEditorController.getJobManager().revisionProperty().addListener(myListener); + myEditorController.getSelection().revisionProperty().addListener(mySelectionListener); } @Override public void close() { if (myEditorController != null) { + myEditorController.getSelection().revisionProperty().removeListener(mySelectionListener); myEditorController.getJobManager().revisionProperty().removeListener(myListener); } } @@ -113,6 +131,11 @@ public class SceneBuilderImpl implements SceneBuilder { try { String fxmlText = FXOMDocument.readContentFromURL(myFileURL); myEditorController.setFxmlTextAndLocation(fxmlText, myFileURL); + + int[][] selectionState = mySelectionState.get(fxmlText); + if (selectionState != null) { + restoreSelection(selectionState); + } } catch (Throwable e) { myEditorCallback.handleError(e); @@ -121,4 +144,133 @@ public class SceneBuilderImpl implements SceneBuilder { mySkipChanges = false; } } + + private int[][] getSelectionState() { + AbstractSelectionGroup group = myEditorController.getSelection().getGroup(); + if (group instanceof ObjectSelectionGroup) { + Set items = ((ObjectSelectionGroup)group).getItems(); + int[][] state = new int[items.size()][]; + int index = 0; + + for (FXOMObject item : items) { + IntArrayList path = new IntArrayList(); + componentToPath(item, path); + state[index++] = path.toArray(); + } + + return state; + } + + return null; + } + + private static void componentToPath(FXOMObject component, IntArrayList path) { + FXOMObject parent = component.getParentObject(); + + if (parent != null) { + path.add(0, component.getParentProperty().getValues().indexOf(component)); + componentToPath(parent, path); + } + } + + private void restoreSelection(int[][] state) { + Collection newSelection = new ArrayList(); + FXOMObject rootComponent = myEditorController.getFxomDocument().getFxomRoot(); + + for (int[] path : state) { + pathToComponent(newSelection, rootComponent, path, 0); + } + + myEditorController.getSelection().select(newSelection); + } + + private static void pathToComponent(Collection components, FXOMObject component, int[] path, int index) { + if (index == path.length) { + components.add(component); + } + else { + List children = Collections.emptyList(); + Map properties = ((FXOMInstance)component).getProperties(); + for (Map.Entry entry : properties.entrySet()) { + FXOMProperty value = entry.getValue(); + if (value instanceof FXOMPropertyC) { + children = ((FXOMPropertyC)value).getValues(); + break; + } + } + + int componentIndex = path[index]; + if (0 <= componentIndex && componentIndex < children.size()) { + pathToComponent(components, children.get(componentIndex), path, index + 1); + } + } + } + + private static class FixedHashMap extends HashMap { + private final int mySize; + private final List myKeys = new LinkedList(); + + public FixedHashMap(int size) { + mySize = size; + } + + @Override + public V put(K key, V value) { + if (!myKeys.contains(key)) { + if (myKeys.size() >= mySize) { + remove(myKeys.remove(0)); + } + myKeys.add(key); + } + return super.put(key, value); + } + + @Override + public V get(Object key) { + if (myKeys.contains(key)) { + int index = myKeys.indexOf(key); + int last = myKeys.size() - 1; + myKeys.set(index, myKeys.get(last)); + myKeys.set(last, (K)key); + } + return super.get(key); + } + } + + private static final int[] EMPTY_INTS = new int[0]; + + private static class IntArrayList { + private int[] myData = EMPTY_INTS; + private int mySize; + + public void add(int index, int element) { + if (index > mySize || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize); + } + + ensureCapacity(mySize + 1); + System.arraycopy(myData, index, myData, index + 1, mySize - index); + myData[index] = element; + mySize++; + } + + public void ensureCapacity(int minCapacity) { + int oldCapacity = myData.length; + if (minCapacity > oldCapacity) { + int[] oldData = myData; + int newCapacity = oldCapacity * 3 / 2 + 1; + if (newCapacity < minCapacity) { + newCapacity = minCapacity; + } + myData = new int[newCapacity]; + System.arraycopy(oldData, 0, myData, 0, mySize); + } + } + + public int[] toArray() { + int[] result = new int[mySize]; + System.arraycopy(myData, 0, result, 0, mySize); + return result; + } + } } \ No newline at end of file diff --git a/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml b/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml index e0372107d51a..6b65da2e0774 100644 --- a/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml +++ b/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml @@ -4,7 +4,17 @@ 1.0 JetBrains - This plugin provides JavaFX2 support. - + JavaFX support. + The following features are available: +
      +
    • Dedicated file type.
    • +
    • Ability to create a project with the special file and directory structure.
    • +
    • JavaFX-aware coding assistance (code completion, search, navigation and refactoring in JavaFX-specific source files).
    • +
    • Integration with JavaFX Scene Builder.
    • +
    • JavaFX application packaging capabilities.
    • +
    + ]]> + diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java index 2de1bc61d599..384d0859f82d 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.javaFX; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -29,7 +30,7 @@ import java.util.Set; */ public class FxmlDataExternalizer implements DataExternalizer> { @Override - public void save(DataOutput out, Set value) throws IOException { + public void save(@NotNull DataOutput out, Set value) throws IOException { out.writeInt(value.size()); for (String s : value) { out.writeUTF(s); @@ -37,7 +38,7 @@ public class FxmlDataExternalizer implements DataExternalizer> { } @Override - public Set read(DataInput in) throws IOException { + public Set read(@NotNull DataInput in) throws IOException { final int size = in.readInt(); final Set result = new HashSet(size); diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java index 1caf0a037fb3..e5c39157ae8e 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java @@ -58,11 +58,13 @@ public class JavaFxControllerClassIndex extends ScalarIndexExtension { return myDataIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -133,7 +135,7 @@ public class JavaFxControllerClassIndex extends ScalarIndexExtension { super(StdFileTypes.XML); } @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return JavaFxFileTypeFactory.isFxml(file); } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java index 50c8b8493970..2178fd89a7d9 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java @@ -81,11 +81,13 @@ public class JavaFxCustomComponentsIndex extends FileBasedIndexExtension> getValueExternalizer() { return myDataExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -97,6 +99,7 @@ public class JavaFxCustomComponentsIndex extends FileBasedIndexExtension getKeyDescriptor() { return myKeyDescriptor; diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java index e0fe90a2ea79..fcaaada562ca 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java @@ -42,11 +42,13 @@ public class JavaFxIdsIndex extends FileBasedIndexExtension> return myDataIndexer; } + @NotNull @Override public DataExternalizer> getValueExternalizer() { return myDataExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -58,6 +60,7 @@ public class JavaFxIdsIndex extends FileBasedIndexExtension> return KEY; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; diff --git a/plugins/junit/src/META-INF/plugin.xml b/plugins/junit/src/META-INF/plugin.xml index d023807439dc..969fec8f58bc 100644 --- a/plugins/junit/src/META-INF/plugin.xml +++ b/plugins/junit/src/META-INF/plugin.xml @@ -16,7 +16,18 @@ JUnit - Provides possibility to run JUnit 3.x and 4.x tests and view their results + + JUnit tests. + The following features are available: +
      +
    • Ability to create JUnit 3.x or JUnit 4.x tests.
    • +
    • Navigation between a test and test subject.
    • +
    • Running tests.
    • +
    • Viewing test results in the dedicated Test Runner tab of the Run tool window.
    • +
    + ]]> +
    1.0 JetBrains diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java index 614332fcadd4..e80920890f48 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -666,14 +666,14 @@ public class MavenIndex { } private static class SetDescriptor implements DataExternalizer> { - public void save(DataOutput s, Set set) throws IOException { + public void save(@NotNull DataOutput s, Set set) throws IOException { s.writeInt(set.size()); for (String each : set) { s.writeUTF(each); } } - public Set read(DataInput s) throws IOException { + public Set read(@NotNull DataInput s) throws IOException { int count = s.readInt(); Set result = new THashSet(count); while (count-- > 0) { diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 337fe0c5840f..5ef7e212f02b 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -2,7 +2,21 @@ org.jetbrains.idea.maven Maven Integration - Import Maven projects and execute Maven goals + + Maven support. + The following features are available: +
      +
    • Maven Projects tool window.
    • +
    • Dedicated module type.
    • +
    • Maven repositories support.
    • +
    • Full editing support for pom.xml file.
    • +
    • Possibility to import Maven projects.
    • +
    • Running and debugging Maven goals.
    • +
    • Compiling.
    • +
    + ]]> +
    JetBrains diff --git a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java index 370f07fab505..de96b39705e7 100644 --- a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java +++ b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.lang.properties.xml; import com.intellij.ide.highlighter.XmlFileType; @@ -52,16 +67,19 @@ public class XmlPropertiesIndex extends FileBasedIndexExtension getKeyDescriptor() { return this; } + @NotNull @Override public DataExternalizer getValueExternalizer() { return ENUMERATOR_STRING_DESCRIPTOR; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return this; @@ -78,7 +96,7 @@ public class XmlPropertiesIndex extends FileBasedIndexExtension>> createExternalizer() { return new DataExternalizer>>() { @Override - public void save(DataOutput out, Map> value) throws IOException { + public void save(@NotNull DataOutput out, Map> value) throws IOException { out.writeInt(value.size()); ArrayList keys = new ArrayList(value.keySet()); Collections.sort(keys); @@ -117,7 +118,7 @@ public class SvnLoadedBrachesStorage { } @Override - public Map> read(DataInput in) throws IOException { + public Map> read(@NotNull DataInput in) throws IOException { final HashMap> map = new HashMap>(); int mapSize = in.readInt(); for (int i = 0; i < mapSize; i++) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java index 2fd8b8b6dfa8..5d7bd6d3aa61 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -28,6 +28,7 @@ import com.intellij.util.containers.MultiMap; import com.intellij.util.continuation.TaskDescriptor; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.history.CopyData; @@ -88,7 +89,7 @@ public class SvnBranchPointsCalculator { } private static class BranchDataExternalizer implements DataExternalizer> { - public void save(DataOutput out, TreeMap value) throws IOException { + public void save(@NotNull DataOutput out, TreeMap value) throws IOException { out.writeInt(value.size()); for (Map.Entry entry : value.entrySet()) { out.writeUTF(entry.getKey()); @@ -100,7 +101,7 @@ public class SvnBranchPointsCalculator { } } - public TreeMap read(DataInput in) throws IOException { + public TreeMap read(@NotNull DataInput in) throws IOException { final TreeMap result = new TreeMap(); final int num = in.readInt(); diff --git a/plugins/ui-designer-core/src/META-INF/plugin.xml b/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml similarity index 58% rename from plugins/ui-designer-core/src/META-INF/plugin.xml rename to plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml index 18d7453c0226..ede0d2b92f01 100644 --- a/plugins/ui-designer-core/src/META-INF/plugin.xml +++ b/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml @@ -1,12 +1,6 @@ - UI Designer (Core) - com.intellij.ui-designer-new - - Provides shared functionality for visual editing plugins. - - JetBrains - messages.DesignerBundle + com.intellij.modules.lang @@ -19,10 +13,6 @@ - - - - diff --git a/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java b/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java index 7f29d4e3d865..4aee4999f707 100644 --- a/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java +++ b/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java @@ -73,6 +73,12 @@ public abstract class DesignerEditor extends UserDataHolderBase implements FileE return myDesignerPanel.getPreferredFocusedComponent(); } + @NotNull + @Override + public String getName() { + return "Design"; + } + @Override public void dispose() { myDesignerPanel.dispose(); diff --git a/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java b/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java index f2d2b9a05a02..defecc586594 100644 --- a/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java +++ b/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java @@ -35,7 +35,6 @@ import org.jetbrains.jps.builders.java.JavaBuilderUtil; import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; import org.jetbrains.jps.builders.logging.ProjectBuilderLogger; import org.jetbrains.jps.incremental.*; -import org.jetbrains.jps.incremental.instrumentation.BaseInstrumentingBuilder; import org.jetbrains.jps.incremental.instrumentation.ClassProcessingBuilder; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.messages.CompilerMessage; @@ -123,7 +122,7 @@ public class FormsInstrumenter extends FormsBuilder { } } finally { - context.processMessage(new ProgressMessage("Finished instrumenting forms [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Finished instrumenting forms [" + chunk.getPresentableShortName() + "]")); } return ExitCode.OK; @@ -197,14 +196,14 @@ public class FormsInstrumenter extends FormsBuilder { addBinding(compiled.getSourceFile(), formFile, instrumented); try { - context.processMessage(new ProgressMessage("Instrumenting forms... [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Instrumenting forms... [" + chunk.getPresentableShortName() + "]")); final BinaryContent originalContent = compiled.getContent(); final ClassReader classReader = new ClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength()); - final int version = BaseInstrumentingBuilder.getClassFileVersion(classReader); - final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(BaseInstrumentingBuilder.getAsmClassWriterFlags(version), finder); + final int version = ClassProcessingBuilder.getClassFileVersion(classReader); + final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(ClassProcessingBuilder.getAsmClassWriterFlags(version), finder); final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, nestedFormsLoader, false, classWriter); final byte[] patchedBytes = codeGenerator.patchClass(classReader); if (patchedBytes != null) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java index 18f23044ac0f..c9702518612f 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -55,11 +55,13 @@ public class FormClassIndex extends ScalarIndexExtension { return myDataIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.GUI_DESIGNER_FORM); diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java index 82e218ff65c1..f34f0fd67cb4 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java @@ -132,21 +132,24 @@ public class XsltSymbolIndex extends FileBasedIndexExtension getValueExternalizer() { return new EnumDataDescriptor(Kind.class); } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML) { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !(file.getFileSystem() instanceof JarFileSystem); } }; diff --git a/python/psi-api/src/com/jetbrains/python/PythonFileType.java b/python/psi-api/src/com/jetbrains/python/PythonFileType.java index d940be65f732..d3d78c5ab98f 100644 --- a/python/psi-api/src/com/jetbrains/python/PythonFileType.java +++ b/python/psi-api/src/com/jetbrains/python/PythonFileType.java @@ -16,11 +16,15 @@ package com.jetbrains.python; import com.intellij.lang.Language; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; import icons.PythonPsiApiIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,6 +45,7 @@ import java.util.regex.Pattern; */ public class PythonFileType extends LanguageFileType { private static final Pattern ENCODING_PATTERN = Pattern.compile("coding[:=]\\s*([-\\w.]+)"); + public static final int MAX_CHARSET_ENCODING_LINE = 2; public static PythonFileType INSTANCE = new PythonFileType(); @@ -100,14 +105,28 @@ public class PythonFileType extends LanguageFileType { } @Nullable - public static String getCharsetFromEncodingDeclaration(String content) { + public static String getCharsetFromEncodingDeclaration(@NotNull PsiFile file) { + final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); + final String content; + if (document != null && document.getLineCount() > MAX_CHARSET_ENCODING_LINE) { + final int offset = document.getLineEndOffset(MAX_CHARSET_ENCODING_LINE); + content = document.getText(TextRange.create(0, offset)); + } + else { + content = file.getText(); + } + return getCharsetFromEncodingDeclaration(content); + } + + @Nullable + private static String getCharsetFromEncodingDeclaration(@Nullable String content) { if (content == null || content.isEmpty()) { return null; } try { final BufferedReader reader = new BufferedReader(new StringReader(content)); try { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_CHARSET_ENCODING_LINE; i++) { final String line = reader.readLine(); if (line == null) { return null; diff --git a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java index b4d83600b7b9..9a835315486f 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java @@ -137,13 +137,12 @@ public class PydevConsoleExecuteActionHandler extends ProcessBackedConsoleExecut // multiline strings handling if (myInMultilineStringState != null) { - if (PyConsoleUtil.isDoubleQuoteMultilineStarts(line)) { + if (PyConsoleUtil.isDoubleQuoteMultilineStarts(line) || PyConsoleUtil.isSingleQuoteMultilineStarts(line)) { myInMultilineStringState = null; // restore language console.setLanguage(PythonLanguage.getInstance()); console.setPrompt(PyConsoleUtil.ORDINARY_PROMPT); - } - else { + } else { return; } } diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java index 9c610e768b28..728056cca301 100644 --- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java +++ b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java @@ -221,7 +221,7 @@ public class RunPythonConsoleAction extends AnAction implements DumbAware { final String path = Joiner.on(", ").join(Collections2.transform(pythonPath, new Function() { @Override public String apply(String input) { - return "'" + input.replace("\\", "\\\\") + "'"; + return "'" + input.replace("\\", "\\\\").replace("'", "\\'") + "'"; } })); diff --git a/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java b/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java index 536074e51d39..0b5c93c8dbaa 100644 --- a/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java @@ -75,7 +75,7 @@ public class PyByteLiteralInspection extends PyInspection { ); } - final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file.getText()); + final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file); try { if (charsetString != null && !Charset.forName(charsetString).equals(Charset.forName("US-ASCII"))) default_bytes = false; diff --git a/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java b/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java index 58e97044c4ab..d41cfbeea3cb 100644 --- a/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java @@ -62,7 +62,7 @@ public class PyMandatoryEncodingInspection extends PyInspection { @Override public void visitPyFile(PyFile node) { - final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(node.getText()); + final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(node); if (charsetString == null) { TextRange tr = new TextRange(0,0); ProblemsHolder holder = getHolder(); diff --git a/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java b/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java index 3038b64710d1..5fd0e565a6f8 100644 --- a/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java @@ -69,7 +69,7 @@ public class PyNonAsciiCharInspection extends PyInspection { if (LanguageLevel.forElement(node).isPy3K()) return; PsiFile file = node.getContainingFile(); // can't cache this in the instance, alas if (file == null) return; - final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file.getText()); + final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file); boolean hasNonAscii = false; diff --git a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java index f3fddbac3a8b..1b3dfc63b61f 100644 --- a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java @@ -24,7 +24,8 @@ import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.util.containers.hash.HashMap; -import com.intellij.util.containers.hash.HashSet; +import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; +import com.jetbrains.python.codeInsight.dataflow.scope.Scope; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.search.PySuperMethodsSearch; import com.jetbrains.python.psi.types.PyModuleType; @@ -34,9 +35,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Collection; import java.util.Map; -import java.util.Set; import java.util.regex.Pattern; /** @@ -71,17 +70,10 @@ public class PyPep8NamingInspection extends PyInspection { public void visitPyAssignmentStatement(PyAssignmentStatement node) { final PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class, true, PyClass.class); if (function == null) return; - final Collection globalStatements = PsiTreeUtil.findChildrenOfType(function, PyGlobalStatement.class); - final Set globals = new HashSet(); - for (PyGlobalStatement statement : globalStatements) { - final PyTargetExpression[] statementGlobals = statement.getGlobals(); - for (PyTargetExpression global : statementGlobals) { - globals.add(global.getName()); - } - } + final Scope scope = ControlFlowCache.getScope(function); for (PyExpression expression : node.getTargets()) { final String name = expression.getName(); - if (name == null || globals.contains(name)) continue; + if (name == null || scope.isGlobal(name)) continue; if (expression instanceof PyTargetExpression) { final PyExpression qualifier = ((PyTargetExpression)expression).getQualifier(); if (qualifier != null) { diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index 82a5fd9590ac..aaf058ca3c6d 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -50,7 +50,9 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; import com.intellij.remotesdk.RemoteFile; +import com.intellij.remotesdk.RemoteSdkAdditionalData; import com.intellij.remotesdk.RemoteSdkCredentials; +import com.intellij.remotesdk2.RemoteSdkAdditionalData2; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.SystemProperties; @@ -778,10 +780,17 @@ public class PyPackageManagerImpl extends PyPackageManager { if (homePath == null) { throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Cannot find interpreter for SDK"); } - if (sdkData instanceof RemoteSdkCredentials) { //remote interpreter - final RemoteSdkCredentials remoteSdkCredentials = (RemoteSdkCredentials)sdkData; + if (sdkData instanceof RemoteSdkAdditionalData2) { //remote interpreter + RemoteSdkCredentials remoteSdkCredentials; + try { + remoteSdkCredentials = ((RemoteSdkAdditionalData2)sdkData).getRemoteSdkCredentials(); + } + catch (InterruptedException e) { + LOG.error(e); + remoteSdkCredentials = null; + } final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance(); - if (manager != null) { + if (manager != null && remoteSdkCredentials != null) { final List cmdline = new ArrayList(); cmdline.add(homePath); cmdline.add(RemoteFile.detectSystemByPath(homePath).createRemoteFile(helperPath).getPath()); diff --git a/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java b/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java index 105aec5c0f7b..f743b8ec19f2 100644 --- a/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java +++ b/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java @@ -70,11 +70,13 @@ public class PyModuleNameIndex extends ScalarIndexExtension { return myDataIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(PythonFileType.INSTANCE); diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java index 40e34f174acc..ca7c52a44fbc 100644 --- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java +++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java @@ -27,9 +27,12 @@ import com.intellij.openapi.projectRoots.SdkAdditionalData; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.remotesdk.RemoteCredentials; import com.intellij.remotesdk.RemoteInterpreterException; import com.intellij.remotesdk.RemoteSdkCredentials; import com.intellij.remotesdk.RemoteSshProcess; +import com.intellij.remotesdk2.VagrantBasedCredentialsHolder; +import com.intellij.util.Consumer; import com.intellij.util.NullableConsumer; import com.intellij.util.PathMappingSettings; import com.jetbrains.python.PythonHelpersLocator; @@ -49,7 +52,7 @@ public abstract class PythonRemoteInterpreterManager { public final static ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.remoteInterpreterManager"); public static final String WEB_DEPLOYMENT_PLUGIN_IS_DISABLED = - "Remote interpreter can't be executed. Please enable the Remote Hosts Access plugin."; + "Remote interpreter can't be executed. Please enable the Remote Hosts Access plugin."; //TODO: this message is incorrect public abstract ProcessHandler startRemoteProcess(@Nullable Project project, @NotNull PyRemoteSdkCredentials data, @@ -153,5 +156,9 @@ public abstract class PythonRemoteInterpreterManager { super(WEB_DEPLOYMENT_PLUGIN_IS_DISABLED); } } + + public abstract RemoteCredentials getVagrantRemoteCredentials(VagrantBasedCredentialsHolder data); + + public abstract RemoteCredentials getCredentialsBySftpServerId(String id); } diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java b/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java index c2680224e28a..8d7ea12aa5ac 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java @@ -35,6 +35,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import static com.intellij.openapi.util.JDOMExternalizer.loadStringsList; + /** * @author traff */ @@ -181,16 +183,7 @@ public class PythonSdkAdditionalData implements SdkAdditionalData { return files; } - protected static List loadStringsList(Element element, String rootName, String attrName) { - final List paths = new LinkedList(); - if (element != null) { - @NotNull final List list = element.getChildren(rootName); - for (Object o : list) { - paths.add(((Element)o).getAttribute(attrName).getValue()); - } - } - return paths; - } + public Set getAddedPathFiles() { return getPathsAsVirtualFiles(myAddedPaths); diff --git a/python/testSrc/com/jetbrains/python/PyEncodingTest.java b/python/testSrc/com/jetbrains/python/PyEncodingTest.java index cccd6d45cfde..608b8396c04a 100644 --- a/python/testSrc/com/jetbrains/python/PyEncodingTest.java +++ b/python/testSrc/com/jetbrains/python/PyEncodingTest.java @@ -15,12 +15,12 @@ */ package com.jetbrains.python; -import junit.framework.TestCase; +import com.jetbrains.python.fixtures.PyTestCase; /** * @author yole */ -public class PyEncodingTest extends TestCase { +public class PyEncodingTest extends PyTestCase { public void testEncodingEmacs() { doTest("#!/usr/bin/python\n# -*- coding: iso-8859-15 -*-\nimport os, sys", "iso-8859-15"); } @@ -33,7 +33,8 @@ public class PyEncodingTest extends TestCase { doTest("#!/usr/local/bin/python\n# coding: latin-1\nimport os, sys", "iso-8859-1"); } - private static void doTest(final String text, final String expected) { - assertEquals(expected, PythonFileType.getCharsetFromEncodingDeclaration(text)); + private void doTest(final String text, final String expected) { + myFixture.configureByText(PythonFileType.INSTANCE, text); + assertEquals(expected, PythonFileType.getCharsetFromEncodingDeclaration(myFixture.getFile())); } } diff --git a/updater/src/com/intellij/updater/Runner.java b/updater/src/com/intellij/updater/Runner.java index 966a4a05896a..9f776b440256 100644 --- a/updater/src/com/intellij/updater/Runner.java +++ b/updater/src/com/intellij/updater/Runner.java @@ -24,15 +24,13 @@ public class Runner { private static final String NEW_BUILD_DESCRIPTION = "new.build.description"; public static void main(String[] args) throws Exception { - if (args.length >= 7 && "create".equals(args[0])) { + if (args.length >= 6 && "create".equals(args[0])) { String oldVersionDesc = args[1]; String newVersionDesc = args[2]; String oldFolder = args[3]; String newFolder = args[4]; String patchFile = args[5]; - - String logFolder = args[6]; - initLogger(logFolder); + initLogger(); List ignoredFiles = extractFiles(args, "ignored"); List criticalFiles = extractFiles(args, "critical"); @@ -41,9 +39,7 @@ public class Runner { } else if (args.length >= 2 && "install".equals(args[0])) { String destFolder = args[1]; - - String logFolder = args.length >= 3 ? args[2] : null; - initLogger(logFolder); + initLogger(); logger.info("destFolder: " + destFolder); install(destFolder); @@ -59,7 +55,8 @@ public class Runner { return fileLogDir.isDirectory() && fileLogDir.canWrite() && fileLogDir.getUsableSpace() >= 1000000; } - private static String getLogDir(String logFolder) { + private static String getLogDir() { + String logFolder = System.getProperty("idea.updater.log"); if (logFolder == null || !isValidLogDir(logFolder)) { logFolder = System.getProperty("java.io.tmpdir"); if (!isValidLogDir(logFolder)) { @@ -69,9 +66,10 @@ public class Runner { return logFolder; } - public static void initLogger(String logFolder) { +// public static void initLogger(String logFolder) { + public static void initLogger() { if (logger == null) { - logFolder = getLogDir(logFolder); + String logFolder = getLogDir(); FileAppender update = new FileAppender(); update.setFile(new File(logFolder, "idea_updater.log").getAbsolutePath()); diff --git a/updater/testSrc/com/intellij/updater/DigesterTest.java b/updater/testSrc/com/intellij/updater/DigesterTest.java index a7ec965359ee..a2ca3005cf5a 100644 --- a/updater/testSrc/com/intellij/updater/DigesterTest.java +++ b/updater/testSrc/com/intellij/updater/DigesterTest.java @@ -10,12 +10,13 @@ import static org.junit.Assert.assertEquals; public class DigesterTest extends UpdaterTestCase { @Test public void testBasics() throws Exception { +// Runner.initLogger(System.getProperty("java.io.tmpdir")); + Runner.initLogger(); Map checkSums = Digester.digestFiles(getDataDir(), Collections.emptyList(), TEST_UI); assertEquals(12, checkSums.size()); assertEquals(CHECKSUMS.README_TXT, (long)checkSums.get("Readme.txt")); assertEquals(CHECKSUMS.FOCUSKILLER_DLL, (long)checkSums.get("bin/focuskiller.dll")); assertEquals(CHECKSUMS.BOOTSTRAP_JAR, (long)checkSums.get("lib/bootstrap.jar")); - Runner.initLogger(System.getProperty("java.io.tmpdir")); } } \ No newline at end of file diff --git a/updater/testSrc/com/intellij/updater/RunnerTest.java b/updater/testSrc/com/intellij/updater/RunnerTest.java index 4813db1711b3..7ac850139a3e 100644 --- a/updater/testSrc/com/intellij/updater/RunnerTest.java +++ b/updater/testSrc/com/intellij/updater/RunnerTest.java @@ -11,7 +11,8 @@ public class RunnerTest extends UpdaterTestCase { @Test public void testExtractingFiles() throws Exception { String[] args = {"bar", "ignored=xxx;yyy;zzz/zzz", "critical=", "ignored=aaa", "baz", "critical=ccc"}; - Runner.initLogger(System.getProperty("java.io.tmpdir")); +// Runner.initLogger(System.getProperty("java.io.tmpdir")); + Runner.initLogger(); assertEquals(Arrays.asList("xxx", "yyy", "zzz/zzz", "aaa"), Runner.extractFiles(args, "ignored")); diff --git a/updater/testSrc/com/intellij/updater/UpdaterTestCase.java b/updater/testSrc/com/intellij/updater/UpdaterTestCase.java index 82d7bbe860c7..9d3b5804d2d2 100644 --- a/updater/testSrc/com/intellij/updater/UpdaterTestCase.java +++ b/updater/testSrc/com/intellij/updater/UpdaterTestCase.java @@ -25,7 +25,8 @@ public abstract class UpdaterTestCase { @Before public void setUp() throws Exception { - Runner.initLogger(System.getProperty("java.io.tmpdir")); +// Runner.initLogger(System.getProperty("java.io.tmpdir")); + Runner.initLogger(); myTempDirFixture = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture(); myTempDirFixture.setUp(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.java b/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.java index 493f6a50ccda..7ca36a62c2f2 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.java +++ b/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -84,11 +84,13 @@ public class DomFileIndex extends ScalarIndexExtension{ return myDataIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML); diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java b/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java index e724f7b1945e..be9035661247 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java @@ -32,6 +32,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.UnfairTextRange; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -107,8 +108,8 @@ public class HtmlSelectioner extends AbstractWordSelectioner { final ASTNode tagStartEnd = XmlChildRole.START_TAG_END_FINDER.findChild(tag.getNode()); final ASTNode tagEndStart = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(tag.getNode()); if (tagStartEnd != null && tagEndStart != null) { - result.add(new TextRange(tagStartEnd.getTextRange().getEndOffset(), - tagEndStart.getTextRange().getStartOffset())); + result.add(new UnfairTextRange(tagStartEnd.getTextRange().getEndOffset(), + tagEndStart.getTextRange().getStartOffset())); } if (tagStartEnd != null) { result.add(new TextRange(tag.getTextRange().getStartOffset(), diff --git a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java index ed0538bf6820..984bd4997ba0 100644 --- a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java +++ b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -86,16 +86,18 @@ public class Html5CustomAttributesIndex extends ScalarIndexExtension { return myIndexer; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.HTML, StdFileTypes.XHTML) { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return file.isInLocalFileSystem(); } }; diff --git a/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java b/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java index 515522185339..f504b66ba754 100644 --- a/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java +++ b/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -133,11 +133,12 @@ public class SchemaTypeInheritanceIndex extends XmlIndex> { }; } + @NotNull @Override public DataExternalizer> getValueExternalizer() { return new DataExternalizer>() { @Override - public void save(DataOutput out, Set value) throws IOException { + public void save(@NotNull DataOutput out, Set value) throws IOException { out.writeInt(value.size()); for (SchemaTypeInfo key : value) { out.writeUTF(key.getNamespaceUri()); @@ -147,7 +148,7 @@ public class SchemaTypeInheritanceIndex extends XmlIndex> { } @Override - public Set read(DataInput in) throws IOException { + public Set read(@NotNull DataInput in) throws IOException { final Set set = new HashSet(); final int size = in.readInt(); for (int i = 0; i < size; i++) { diff --git a/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.java b/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.java index 97fb7c0d3d53..b3fc55c1a857 100644 --- a/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.java +++ b/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -70,6 +70,7 @@ public class XmlTagNamesIndex extends XmlIndex { }; } + @NotNull @Override public DataExternalizer getValueExternalizer() { return ScalarIndexExtension.VOID_DATA_EXTERNALIZER; diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java index eede27a5a2b9..a00d40dd1172 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 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.intellij.plugins.relaxNG.model.resolve; import com.intellij.ide.highlighter.XmlFileType; @@ -129,16 +144,18 @@ public class RelaxSymbolIndex extends ScalarIndexExtension { }; } + @NotNull @Override public KeyDescriptor getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML, RncFileType.getInstance()) { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !(file.getFileSystem() instanceof JarFileSystem); } }; diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java index 4d58a5524bfe..d5bec52f6091 100644 --- a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java @@ -514,18 +514,23 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx { if (classLoader == null && clazz == null) return file; final URL resource = clazz == null ? classLoader.getResource(file) : clazz.getResource(file); - classLoader = null; - clazz = null; - if (resource == null) { - String message = "Cannot find standard resource. filename:" + file + " class=" + classLoader; - if (ApplicationManager.getApplication().isUnitTestMode()) { - LOG.error(message); - } - else { - LOG.warn(message); - } - return null; + try { + if (resource == null) { + String message = "Cannot find standard resource. filename:" + file + " class=" + clazz + ", classLoader:" + classLoader; + if (ApplicationManager.getApplication().isUnitTestMode()) { + LOG.error(message); + } + else { + LOG.warn(message); + } + + return null; + } + } + finally { + classLoader = null; + clazz = null; } String path = FileUtil.unquote(resource.toString()); @@ -535,7 +540,6 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx { return path; } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.java b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.java index 1e549442011a..fb5242cb3e51 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -95,13 +95,15 @@ public abstract class XmlIndex extends FileBasedIndexExtension { }; } + @NotNull public KeyDescriptor getKeyDescriptor() { return KEY_DESCRIPTOR; } + @NotNull public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(XmlFileType.INSTANCE, DTDFileType.INSTANCE) { - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { FileType fileType = file.getFileType(); final String extension = file.getExtension(); return XmlFileType.INSTANCE.equals(fileType) && "xsd".equals(extension) || diff --git a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.java b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.java index 55cde705430c..923a5cfce4e0 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -107,11 +107,12 @@ public class XmlNamespaceIndex extends XmlIndex { }; } + @NotNull @Override public DataExternalizer getValueExternalizer() { return new DataExternalizer() { @Override - public void save(DataOutput out, XsdNamespaceBuilder value) throws IOException { + public void save(@NotNull DataOutput out, XsdNamespaceBuilder value) throws IOException { out.writeUTF(value.getNamespace() == null ? "" : value.getNamespace()); out.writeUTF(value.getVersion() == null ? "" : value.getVersion()); out.writeInt(value.getTags().size()); @@ -121,7 +122,7 @@ public class XmlNamespaceIndex extends XmlIndex { } @Override - public XsdNamespaceBuilder read(DataInput in) throws IOException { + public XsdNamespaceBuilder read(@NotNull DataInput in) throws IOException { int count; XsdNamespaceBuilder builder = new XsdNamespaceBuilder(in.readUTF(), in.readUTF(), new ArrayList(count = in.readInt()));