Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Bulenkov
2013-11-03 19:04:02 +01:00
49 changed files with 734 additions and 212 deletions
@@ -424,8 +424,13 @@ public abstract class DebugProcessImpl implements DebugProcess {
for (final StepRequest request : stepRequests) {
ThreadReference threadReference = request.thread();
// [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures
if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) {
toDelete.add(request);
try {
if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) {
toDelete.add(request);
}
}
catch (IllegalThreadStateException e) {
LOG.info(e); // undocumented by JDI: may be thrown when querying thread status
}
}
requestManager.deleteEventRequests(toDelete);
@@ -17,6 +17,7 @@ package com.intellij.debugger.engine;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLambdaExpression;
@@ -76,7 +77,8 @@ public class LambdaMethodFilter implements BreakpointStepMethodFilter{
}
public boolean locationMatches(DebugProcessImpl process, Location location) throws EvaluateException {
final VirtualMachineProxyImpl vm = process.getVirtualMachineProxy();
final Method method = location.method();
return method.name().startsWith(LAMBDA_METHOD_PREFIX) && method.isSynthetic();
return method.name().startsWith(LAMBDA_METHOD_PREFIX) && (!vm.canGetSyntheticAttribute() || method.isSynthetic());
}
}
@@ -268,24 +268,19 @@ public class PositionManagerImpl implements PositionManager {
private ReferenceType findNested(final ReferenceType fromClass, final int currentDepth, final PsiClass classToFind, final int requiredDepth, final SourcePosition position) {
final VirtualMachineProxyImpl vmProxy = myDebugProcess.getVirtualMachineProxy();
if (fromClass.isPrepared()) {
try {
//final int lineNumber = position.getLine() + 1;
if (currentDepth < requiredDepth) {
final List<ReferenceType> nestedTypes = vmProxy.nestedTypes(fromClass);
for (ReferenceType nested : nestedTypes) {
final ReferenceType found = findNested(nested, currentDepth + 1, classToFind, requiredDepth, position);
if (found != null) {
// check if enclosing class also has executable code at the same line, and if yes, prefer enclosing class
//return fromClass.locationsOfLine(lineNumber).isEmpty()? found : fromClass;
return found;
}
}
return null;
}
final boolean canGetSynthetic = vmProxy.canGetSyntheticAttribute();
int rangeBegin = Integer.MAX_VALUE;
int rangeEnd = Integer.MIN_VALUE;
for (Location location : fromClass.allLineLocations()) {
@@ -294,8 +289,9 @@ public class PositionManagerImpl implements PositionManager {
continue; // should be a native method, skipping
}
final Method method = location.method();
if (method == null || method.isSynthetic() || method.isBridge() || method.isObsolete()) {
continue; // do not take into account synthetic stuff
if (method == null || (canGetSynthetic && method.isSynthetic()) || method.isBridge()) {
// do not take into account synthetic stuff
continue;
}
final int locationLine = lnumber - 1;
rangeBegin = Math.min(rangeBegin, locationLine);
@@ -67,16 +67,23 @@ public abstract class SuspendContextCommandImpl extends DebuggerCommandImpl {
}
finally{
suspendContext.myInProgress = false;
SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand();
if (postponed != null) {
final Stack<SuspendContextCommandImpl> stack = new Stack<SuspendContextCommandImpl>();
while (postponed != null) {
stack.push(postponed);
postponed = suspendContext.pollPostponedCommand();
if (suspendContext.isResumed()) {
for (SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand(); postponed != null; postponed = suspendContext.pollPostponedCommand()) {
postponed.notifyCancelled();
}
final DebuggerManagerThreadImpl managerThread = suspendContext.getDebugProcess().getManagerThread();
while (!stack.isEmpty()) {
managerThread.pushBack(stack.pop());
}
else {
SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand();
if (postponed != null) {
final Stack<SuspendContextCommandImpl> stack = new Stack<SuspendContextCommandImpl>();
while (postponed != null) {
stack.push(postponed);
postponed = suspendContext.pollPostponedCommand();
}
final DebuggerManagerThreadImpl managerThread = suspendContext.getDebugProcess().getManagerThread();
while (!stack.isEmpty()) {
managerThread.pushBack(stack.pop());
}
}
}
}
@@ -26,11 +26,12 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.ui.MessageCategory;
import com.intellij.util.ui.UIUtil;
import com.sun.jdi.ReferenceType;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
@@ -163,50 +164,41 @@ class ReloadClassesWorker {
processException(e);
}
final Semaphore waitSemaphore = new Semaphore();
waitSemaphore.down();
//noinspection SSBasedInspection
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (project.isDisposed()) {
return;
}
final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager();
breakpointManager.reloadBreakpoints();
debugProcess.getRequestsManager().clearWarnings();
if (LOG.isDebugEnabled()) {
LOG.debug("requests updated");
LOG.debug("time stamp set");
}
myDebuggerSession.refresh(false);
/*
debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
protected void action() throws Exception {
try {
breakpointManager.enableBreakpoints(debugProcess);
try {
if (!project.isDisposed()) {
final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager();
breakpointManager.reloadBreakpoints();
debugProcess.getRequestsManager().clearWarnings();
if (LOG.isDebugEnabled()) {
LOG.debug("requests updated");
LOG.debug("time stamp set");
}
catch (Exception e) {
processException(e);
}
//try {
// virtualMachineProxy.resume();
//}
//catch (Exception e) {
// processException(e);
//}
myDebuggerSession.refresh(false);
}
public Priority getPriority() {
return Priority.HIGH;
}
});
*/
}
catch (Throwable e) {
LOG.error(e);
}
finally {
waitSemaphore.up();
}
}
});
try {
breakpointManager.enableBreakpoints(debugProcess);
}
catch (Exception e) {
processException(e);
waitSemaphore.waitFor();
if (!project.isDisposed()) {
try {
breakpointManager.enableBreakpoints(debugProcess);
}
catch (Exception e) {
processException(e);
}
}
}
@@ -32,10 +32,7 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.LocalVariableProxyImpl;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.jdi.*;
import com.intellij.debugger.settings.NodeRendererSettings;
import com.intellij.debugger.settings.ThreadsViewSettings;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
@@ -462,8 +459,10 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
final ReferenceType thisRefType = thisObjectReference.referenceType();
if (thisRefType instanceof ClassType && thisRefType.equals(location.declaringType()) && thisRefType.name().contains("$")) { // makes sense for nested classes only
final ClassType clsType = (ClassType)thisRefType;
final DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess();
final VirtualMachineProxyImpl vm = debugProcess.getVirtualMachineProxy();
for (Field field : clsType.fields()) {
if (field.isSynthetic() && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
if ((!vm.canGetSyntheticAttribute() || field.isSynthetic()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
final FieldDescriptorImpl fieldDescriptor = myNodeManager.getFieldDescriptor(stackDescriptor, thisObjectReference, field);
myChildren.add(myNodeManager.createNode(fieldDescriptor, evaluationContext));
}
@@ -42,7 +42,7 @@ import static com.intellij.codeInsight.ConditionChecker.Type.*;
import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint;
import static com.intellij.psi.CommonClassNames.*;
class ControlFlowAnalyzer extends JavaElementVisitor {
public class ControlFlowAnalyzer extends JavaElementVisitor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer");
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
private boolean myIgnoreAssertions;
@@ -111,13 +111,21 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
if (method == null) return;
String text = AnnotationUtil.getStringAttributeValue(annotation, null);
if (text == null) return;
if (StringUtil.isNotEmpty(text)) {
String error = checkContract(method, text);
if (error != null) {
PsiAnnotationMemberValue value = annotation.findAttributeValue(null);
assert value != null;
holder.registerProblem(value, error);
return;
}
}
String error = checkContract(method, text);
if (error != null) {
PsiAnnotationMemberValue value = annotation.findAttributeValue(null);
if (Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(annotation, "pure")) &&
PsiType.VOID.equals(method.getReturnType())) {
PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue("pure");
assert value != null;
holder.registerProblem(value, error);
holder.registerProblem(value, "Pure methods must return something, void is not allowed as a return type");
}
}
};
@@ -5,10 +5,11 @@ import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.IOUtil;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentHashMap;
import org.jetbrains.asm4.tree.ClassNode;
@@ -51,24 +52,32 @@ public abstract class CompilerOutputBaseIndex<K, V> {
if (!IndexInfrastructure.getIndexRootDir(indexId).exists()) {
rewriteIndex.set(true);
}
final File storageFile = IndexInfrastructure.getStorageFile(indexId);
final File storageFile = getStorageFile(indexId);
final MapIndexStorage<K, V> indexStorage = new MapIndexStorage<K, V>(storageFile, myKeyDescriptor, myValueExternalizer, 1024);
index = new MapReduceIndex<K, V, ClassNode>(indexId, getIndexer(), indexStorage);
index.setInputIdToDataKeysIndex(new Factory<PersistentHashMap<Integer, Collection<K>>>() {
@Override
public PersistentHashMap<Integer, Collection<K>> create() {
Exception failCause = null;
for (int attempts = 0; attempts < 2; attempts++) {
try {
return FileBasedIndexImpl.createIdToDataKeysIndex(indexId, myKeyDescriptor, new MemoryIndexStorage<K, V>(indexStorage));
}
catch (IOException e) {
failCause = e;
FileUtil.delete(IndexInfrastructure.getInputIndexStorageFile(getIndexId()));
rewriteIndex.set(true);
}
try {
return IOUtil.openCleanOrResetBroken(
new ThrowableComputable<PersistentHashMap<Integer, Collection<K>>, IOException>() {
@Override
public PersistentHashMap<Integer, Collection<K>> compute() throws IOException {
return FileBasedIndexImpl.createIdToDataKeysIndex(indexId, myKeyDescriptor, new MemoryIndexStorage<K, V>(indexStorage));
}
},
new Runnable() {
@Override
public void run() {
FileUtil.delete(getInputIndexStorageFile(getIndexId()));
rewriteIndex.set(true);
}
}
);
}
catch (IOException e) {
throw new RuntimeException("couldn't create index", e);
}
throw new RuntimeException("couldn't create index", failCause);
}
});
final File versionFile = getVersionFile(indexId);
@@ -144,9 +153,4 @@ public abstract class CompilerOutputBaseIndex<K, V> {
protected final ID<K, V> generateIndexId(final String indexName) {
return CompilerOutputIndexUtil.generateIndexId(indexName, myProject);
}
protected final ID<K, V> generateIndexId(final Class aClass) {
final String className = StringUtil.getShortName(aClass);
return generateIndexId(StringUtil.trimEnd(className, "Index"));
}
}
@@ -12,6 +12,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.openapi.util.registry.RegistryValueListener;
@@ -153,16 +154,19 @@ public class CompilerOutputIndexer extends AbstractProjectComponent {
private void doEnable() {
if (myInitialized.compareAndSet(false, true)) {
initTimestampIndex();
File storageFile =
final File storageFile =
IndexInfrastructure.getStorageFile(CompilerOutputIndexUtil.generateIndexId("compilerOutputIndexFileId.enum", myProject));
for (int i = 0; i < 2; i++) {
try {
myFileEnumerator = new PersistentEnumeratorDelegate<String>(storageFile, new EnumeratorStringDescriptor(), 2048);
}
catch (IOException e) {
if (i == 1) throw new RuntimeException(e);
IOUtil.deleteAllFilesStartingWith(storageFile);
}
try {
myFileEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentEnumeratorDelegate<String>, IOException>() {
@Override
public PersistentEnumeratorDelegate<String> compute() throws IOException {
return new PersistentEnumeratorDelegate<String>(storageFile, new EnumeratorStringDescriptor(), 2048);
}
}, storageFile);
}
catch (IOException e) {
throw new RuntimeException(e);
}
CompilerManager.getInstance(myProject).addCompilationStatusListener(new CompilationStatusAdapter() {
@Override
@@ -184,29 +188,35 @@ public class CompilerOutputIndexer extends AbstractProjectComponent {
}
private void initTimestampIndex() {
for (int attempts = 0; attempts < 2; attempts++) {
try {
myFileTimestampsIndex = new PersistentHashMap<String, Long>(IndexInfrastructure.getStorageFile(getFileTimestampsIndexId()),
new EnumeratorStringDescriptor(), new DataExternalizer<Long>() {
final File storageFile = IndexInfrastructure.getStorageFile(getFileTimestampsIndexId());
try {
myFileTimestampsIndex = IOUtil.openCleanOrResetBroken(
new ThrowableComputable<PersistentHashMap<String, Long>, IOException>() {
@Override
public void save(final DataOutput out, final Long value) throws IOException {
out.writeLong(value);
}
public PersistentHashMap<String, Long> compute() throws IOException {
return new PersistentHashMap<String, Long>(storageFile,
new EnumeratorStringDescriptor(), new DataExternalizer<Long>() {
@Override
public void save(final DataOutput out, final Long value) throws IOException {
out.writeLong(value);
}
@Override
public Long read(final DataInput in) throws IOException {
return in.readLong();
@Override
public Long read(final DataInput in) throws IOException {
return in.readLong();
}
});
}
});
}
catch (IOException e) {
FileUtil.delete(IndexInfrastructure.getIndexRootDir(getFileTimestampsIndexId()));
}
if (myFileTimestampsIndex != null) {
return;
}
},
new Runnable() {
public void run() {
FileUtil.delete(IndexInfrastructure.getIndexRootDir(getFileTimestampsIndexId()));
}
}
);
} catch (IOException ex) {
throw new RuntimeException("Timestamps index not initialized", ex);
}
throw new RuntimeException("Timestamps index not initialized");
}
public void reindex(final FileVisitorService visitorService, final @NotNull ProgressIndicator indicator) {
@@ -46,4 +46,7 @@ public class AssertIsNotNull {
@Contract(<warning descr="Method takes 2 parameters, while contract clause number 1 expects 1">"null -> _"</warning>)
void wrongParameterCount(Object a, boolean b) {}
@Contract(pure=<warning descr="Pure methods must return something, void is not allowed as a return type">true</warning>)
void voidPureMethod() {}
}
@@ -116,7 +116,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase {
}
""")
type "r"
assertContains "iterable", "iter"
myFixture.assertPreferredCompletionItems 1, "iter", "iterable"
type '\b'
assertContains "iterable"
@@ -131,7 +131,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase {
assertContains "iterable"
type "r"
assertContains "iterable", "iter"
myFixture.assertPreferredCompletionItems 1, "iter", "iterable"
}
public void testExplicitSelectionShouldSurvive() {
@@ -151,7 +151,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase {
assertEquals 'iterable2', lookup.currentItem.lookupString
type "r"
myFixture.assertPreferredCompletionItems 2, "iterable", "iter", 'iterable2'
myFixture.assertPreferredCompletionItems 2, "iter", "iterable", 'iterable2'
}
@@ -172,7 +172,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase {
assertEquals 'iterable2', lookup.currentItem.lookupString
type "r"
myFixture.assertPreferredCompletionItems 2, "iterable", "iter", 'iterable2'
myFixture.assertPreferredCompletionItems 2, "iter", "iterable", 'iterable2'
}
@@ -1305,7 +1305,7 @@ class Foo {
type 'e'
myFixture.assertPreferredCompletionItems 0, 'itera', 'itex'
type 'r'
myFixture.assertPreferredCompletionItems 0, 'itera', 'iter'
myFixture.assertPreferredCompletionItems 1, 'iter', 'itera'
type '\b'
myFixture.assertPreferredCompletionItems 0, 'itera', 'itex'
}
@@ -1544,9 +1544,9 @@ class Foo {
}
'''
type 'tpl'
myFixture.assertPreferredCompletionItems 0, 'tplMn', 'tpl'
myFixture.assertPreferredCompletionItems 1, 'tpl', 'tplMn'
LookupElementPresentation p = LookupElementPresentation.renderElement(myFixture.lookupElements[1])
LookupElementPresentation p = LookupElementPresentation.renderElement(myFixture.lookupElements[0])
assert p.itemText == 'tpl'
assert !p.tailText
def tabKeyPresentation = KeyEvent.getKeyText(TemplateSettings.TAB_CHAR as int)
@@ -39,12 +39,6 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
return JAVA_1_7;
}
@Override
protected void setUp() throws Exception {
super.setUp();
myFixture.addClass("package org.jetbrains.annotations; public @interface Contract { String value(); }");
}
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath() + "/inspection/dataFlow/fixture/";
Binary file not shown.
@@ -43,11 +43,19 @@ import java.lang.annotation.*;
* <code>@Contract("_, null -> null; _, !null -> !null")</code> - method returns null if its second argument is null and not-null otherwise<br/>
* <code>@Contract("true -> fail")</code> - a typical assertFalse method which throws an exception if <code>true</code> is passed to it<br/>
*
* @author peter
*/
@Documented
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface Contract {
String value();
/**
* Contains the contract clauses describing causal relations between call arguments and the returned value
*/
String value() default "";
/**
* Specifies if this method is pure, i.e. has no visible side effects. This may be used for more precise data flow analysis, and
* to check that the method's return value is actually used in the call place.
*/
boolean pure() default false;
}
@@ -223,15 +223,7 @@ public class CompletionLookupArranger extends LookupArranger {
ensureItemAdded(items, model, byRelevance, relevantSelection);
ensureEverythingVisibleAdded(lookup, model, byRelevance);
ArrayList<LookupElement> result = new ArrayList<LookupElement>(model);
if (result.size() > 1) {
LookupElement first = result.get(0);
if (isLiveTemplate(first) && isPrefixItem(lookup, first, true) && CompletionServiceImpl.isStartMatch(result.get(1), lookup)) {
ContainerUtil.swapElements(result, 0, 1);
}
}
return result;
return new ArrayList<LookupElement>(model);
}
private static void ensureEverythingVisibleAdded(LookupImpl lookup, final LinkedHashSet<LookupElement> model, Iterator<LookupElement> byRelevance) {
@@ -133,7 +133,7 @@ public class LiveTemplateCompletionContributor extends CompletionContributor {
@Override
public boolean skipElement(LookupElement element, CompletionLocation location) {
return element instanceof LiveTemplateLookupElement && ((LiveTemplateLookupElement)element).sudden;
return element instanceof LiveTemplateLookupElement && ((LiveTemplateLookupElement)element).sudden && !Registry.is("ide.completion.autopopup.select.live.templates");
}
}
@@ -522,7 +522,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo
try {
if (editorHighlighter instanceof LayeredLexerEditorHighlighter) {
lexer = LexerEditorHighlighterLexer.getLexerBasedOnLexerHighlighter(text, file, myProject);
lexer = new LexerEditorHighlighterLexer(editorHighlighter, false);
} else {
lexer = highlighter.getHighlightingLexer();
}
@@ -213,7 +213,7 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
}
private int fitLineToEditor(int visualLine) {
return Math.min(myEditor.getVisibleLineCount() - 1, Math.max(0, visualLine));
return Math.max(0, Math.min(myEditor.getVisibleLineCount() - 1, visualLine));
}
private int getOffset(int visualLine, boolean startLine) {
@@ -213,6 +213,7 @@ ide.mac.fix.accessibleLeak=true
projectView.showHierarchyErrors=true
projectView.hide.dot.idea=true
show.live.templates.in.completion=false
ide.completion.autopopup.select.live.templates=false
documentation.component.editor.font=false
ide.completion.show.better.matching.classes=true
@@ -79,13 +79,11 @@ public class ModuleUtilCore {
@Nullable
public static Module findModuleForPsiElement(@NotNull PsiElement element) {
if (!element.isValid()) {
return null;
}
PsiFile containingFile = element.getContainingFile();
if (containingFile == null) {
if (!element.isValid()) return null;
}
else {
if (!containingFile.isValid()) return null;
}
if (containingFile != null && !containingFile.isValid()) return null;
Project project = (containingFile == null ? element : containingFile).getProject();
if (project.isDefault()) return null;
@@ -15,6 +15,7 @@
*/
package com.intellij.util.io;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.SystemProperties;
@@ -184,4 +185,26 @@ public class IOUtil {
throw new RuntimeException(e);
}
}
public static <T> T openCleanOrResetBroken(@NotNull ThrowableComputable<T, IOException> factoryComputable, final File file) throws IOException {
return openCleanOrResetBroken(factoryComputable, new Runnable() {
@Override
public void run() {
deleteAllFilesStartingWith(file);
}
});
}
public static <T> T openCleanOrResetBroken(@NotNull ThrowableComputable<T, IOException> factoryComputable, Runnable cleanupCallback) throws IOException {
for(int i = 0; i < 2; ++i) {
try {
return factoryComputable.compute();
} catch (IOException ex) {
if (i == 1) throw ex;
cleanupCallback.run();
}
}
return null;
}
}
@@ -32,6 +32,13 @@ public interface VcsLog {
@NotNull
List<Hash> getSelectedCommits();
/**
* Returns details of the selected commits if all of them have been loaded.
* To avoid data inconsistency, if at least one of the selected commits have no details loaded, empty list is returned.
*/
@NotNull
List<VcsFullCommitDetails> getSelectedDetails();
/**
* Returns details of the given commit, if they have been already loaded.
* In most cases they are already in the cache, and will be returned.
@@ -0,0 +1,27 @@
/*
* 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 com.intellij.vcs.log;
import com.intellij.openapi.actionSystem.DataKey;
/**
* Provides {@link DataKey DataKeys} which can be used by actions to access data available in the VCS log.
*/
public class VcsLogDataKeys {
public static DataKey<VcsLog> VSC_LOG = DataKey.create("Vcs.Log");
}
@@ -18,4 +18,11 @@ public interface VcsLogSettings {
*/
int getRecentCommitsCount();
/**
* Checks if the branches panel should be displayed or hidden.
*/
boolean isShowBranchesPanel();
void setShowBranchesPanel(boolean show);
}
@@ -12,18 +12,22 @@
<projectService serviceInterface="com.intellij.vcs.log.impl.VcsLogManager" serviceImplementation="com.intellij.vcs.log.impl.VcsLogManager"/>
<projectService serviceInterface="com.intellij.vcs.log.VcsLogSettings" serviceImplementation="com.intellij.vcs.log.impl.VcsLogSettingsImpl"/>
<projectService serviceInterface="com.intellij.vcs.log.data.VcsLogUiProperties" serviceImplementation="com.intellij.vcs.log.data.VcsLogUiProperties"/>
<projectService serviceInterface="com.intellij.vcs.log.VcsLog" serviceImplementation="com.intellij.vcs.log.impl.VcsLogImpl" />
</extensions>
<actions>
<action class="com.intellij.vcs.log.ui.VcsLogCopyHashAction" id="Vcs.Log.CopyHash"
icon="AllIcons.Actions.Copy" text="Copy Hash" description="Copy hash value of the selected commit to clipboard" />
<action class="com.intellij.vcs.log.ui.VcsLogCreatePatchAction" id="Vcs.Log.CreatePatch" />
<action class="com.intellij.vcs.log.ui.VcsLogQuickSettingsActions" id="Vcs.Log.QuickSettings"
icon="AllIcons.General.Gear" text="Quick Settings" description="Quick Settings" />
<group id="Vcs.Log.Toolbar">
<reference id="Vcs.Log.CopyHash"/>
<reference id="Vcs.Log.QuickSettings" />
</group>
<group id="Vcs.Log.ContextMenu">
<reference id="Vcs.Log.CopyHash"/>
<reference id="Vcs.Log.CreatePatch"/>
</group>
</actions>
@@ -8,26 +8,22 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* TODO use VcsRef instead of String
*/
public class VcsLogBranchFilter implements VcsLogGraphFilter {
@NotNull private final Collection<Hash> myMatchingHeads;
private final String myBranchName;
@NotNull private final String myBranchName;
public VcsLogBranchFilter(Collection<VcsRef> allRefs, final String branchName) {
myBranchName = branchName;
public VcsLogBranchFilter(@NotNull Collection<VcsRef> allRefs, @NotNull final String selectedBranchName) {
myBranchName = selectedBranchName;
myMatchingHeads = ContainerUtil.mapNotNull(allRefs, new Function<VcsRef, Hash>() {
@Override
public Hash fun(VcsRef ref) {
if (ref.getName().equals(branchName)) {
if (ref.getName().equals(selectedBranchName)) {
return ref.getCommitHash();
}
return null;
}
});
}
@Override
@@ -44,4 +40,5 @@ public class VcsLogBranchFilter implements VcsLogGraphFilter {
public String getBranchName() {
return myBranchName;
}
}
@@ -20,6 +20,8 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.ui.VcsLogUI;
import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,25 +34,19 @@ import java.util.List;
*/
public class VcsLogImpl implements VcsLog {
private final VcsLogManager myLogManager;
@NotNull private final VcsLogDataHolder myDataHolder;
@NotNull private final VcsLogUI myUi;
public VcsLogImpl(VcsLogManager vcsLogManager) {
myLogManager = vcsLogManager;
}
/**
* Checks if the log is initialized.
* TODO Temporary method until the old Git log is switched off and removed
*/
public boolean isReady() {
return myLogManager.getDataHolder() != null && myLogManager.getLogUi() != null;
public VcsLogImpl(@NotNull VcsLogDataHolder holder, @NotNull VcsLogUI ui) {
myDataHolder = holder;
myUi = ui;
}
@Override
@NotNull
public List<Hash> getSelectedCommits() {
List<Hash> hashes = ContainerUtil.newArrayList();
JBTable table = myLogManager.getLogUi().getTable();
JBTable table = myUi.getTable();
for (int row : table.getSelectedRows()) {
Hash hash = ((AbstractVcsLogTableModel)table.getModel()).getHashAtRow(row);
if (hash != null) {
@@ -60,10 +56,26 @@ public class VcsLogImpl implements VcsLog {
return hashes;
}
@NotNull
@Override
public List<VcsFullCommitDetails> getSelectedDetails() {
List<VcsFullCommitDetails> details = ContainerUtil.newArrayList();
JBTable table = myUi.getTable();
for (int row : table.getSelectedRows()) {
AbstractVcsLogTableModel model = (AbstractVcsLogTableModel)table.getModel();
VcsFullCommitDetails commitDetails = model.getFullCommitDetails(row);
if (commitDetails == null) {
return ContainerUtil.emptyList();
}
details.add(commitDetails);
}
return details;
}
@Override
@Nullable
public VcsFullCommitDetails getDetailsIfAvailable(@NotNull final Hash hash) {
return myLogManager.getDataHolder().getCommitDetailsGetter().getCommitDataIfAvailable(hash);
return myDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(hash);
}
@Nullable
@@ -17,6 +17,7 @@ public class VcsLogSettingsImpl implements VcsLogSettings, PersistentStateCompon
public static class State {
public int RECENT_COMMITS_COUNT = 1000;
public boolean SHOW_BRANCHES_PANEL = false;
}
@Nullable
@@ -35,6 +36,16 @@ public class VcsLogSettingsImpl implements VcsLogSettings, PersistentStateCompon
return myState.RECENT_COMMITS_COUNT;
}
@Override
public boolean isShowBranchesPanel() {
return myState.SHOW_BRANCHES_PANEL;
}
@Override
public void setShowBranchesPanel(boolean show) {
myState.SHOW_BRANCHES_PANEL = show;
}
public void setRecentCommitsBlockSize(int commitCount) {
myState.RECENT_COMMITS_COUNT = commitCount;
}
@@ -0,0 +1,31 @@
/*
* 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 com.intellij.vcs.log.ui;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.actions.CreatePatchFromChangesAction;
public class VcsLogCreatePatchAction extends CreatePatchFromChangesAction {
@Override
public void update(AnActionEvent e) {
Change[] changes;
e.getPresentation().setEnabled((changes = e.getData(VcsDataKeys.CHANGES)) != null && changes.length > 0);
}
}
@@ -0,0 +1,87 @@
/*
* 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 com.intellij.vcs.log.ui;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.vcs.log.VcsLogSettings;
import com.intellij.vcs.log.impl.VcsLogManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
public class VcsLogQuickSettingsActions extends DumbAwareAction {
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
if (project == null) {
return;
}
VcsLogSettings settings = ServiceManager.getService(project, VcsLogSettings.class);
VcsLogManager logManager = ServiceManager.getService(project, VcsLogManager.class);
if (settings == null || logManager == null) {
return;
}
VcsLogUI logUi = logManager.getLogUi();
ActionGroup settingsGroup = new MySettingsActionGroup(settings, logUi);
ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ToolWindowContentUi.POPUP_PLACE, settingsGroup);
int x = 0;
int y = 0;
InputEvent inputEvent = e.getInputEvent();
if (inputEvent instanceof MouseEvent) {
x = ((MouseEvent)inputEvent).getX();
y = ((MouseEvent)inputEvent).getY();
}
popupMenu.getComponent().show(inputEvent.getComponent(), x, y);
}
private static class MySettingsActionGroup extends ActionGroup {
private final VcsLogSettings mySettings;
private final VcsLogUI myUi;
public MySettingsActionGroup(VcsLogSettings settings, VcsLogUI ui) {
mySettings = settings;
myUi = ui;
}
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
return new AnAction[] {
new ToggleAction("Show Branches Panel") {
@Override
public boolean isSelected(AnActionEvent e) {
return mySettings.isShowBranchesPanel();
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
mySettings.setShowBranchesPanel(state);
myUi.setBranchesPanelVisible(state);
}
}
};
}
}
}
@@ -5,6 +5,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.VcsLogFilter;
import com.intellij.vcs.log.VcsLogSettings;
import com.intellij.vcs.log.compressedlist.UpdateRequest;
@@ -16,6 +17,7 @@ import com.intellij.vcs.log.graph.elements.GraphElement;
import com.intellij.vcs.log.graph.elements.Node;
import com.intellij.vcs.log.graphmodel.FragmentManager;
import com.intellij.vcs.log.graphmodel.GraphFragment;
import com.intellij.vcs.log.impl.VcsLogImpl;
import com.intellij.vcs.log.printmodel.SelectController;
import com.intellij.vcs.log.ui.frame.MainFrame;
import com.intellij.vcs.log.ui.frame.VcsLogGraphTable;
@@ -42,6 +44,7 @@ public class VcsLogUI {
@NotNull private final VcsLogColorManager myColorManager;
@NotNull private final VcsLogUiProperties myUiProperties;
@NotNull private final VcsLogFilterer myFilterer;
@NotNull private final VcsLog myLog;
@Nullable private GraphElement prevGraphElement;
@@ -52,7 +55,8 @@ public class VcsLogUI {
myColorManager = manager;
myUiProperties = uiProperties;
myFilterer = new VcsLogFilterer(logDataHolder, this);
myMainFrame = new MainFrame(myLogDataHolder, this, project, uiProperties);
myLog = new VcsLogImpl(myLogDataHolder, this);
myMainFrame = new MainFrame(myLogDataHolder, this, project, settings, uiProperties, myLog);
project.getMessageBus().connect(project).subscribe(VcsLogDataHolder.REFRESH_COMPLETED, new Runnable() {
@Override
public void run() {
@@ -247,4 +251,8 @@ public class VcsLogUI {
ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, task, false, null, this.getMainFrame().getMainComponent());
}
public void setBranchesPanelVisible(boolean visible) {
myMainFrame.setBranchesPanelVisible(visible);
}
}
@@ -8,10 +8,12 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.committed.RepositoryChangesBrowser;
import com.intellij.openapi.vcs.changes.ui.ChangesBrowser;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBLoadingPanel;
import com.intellij.util.ArrayUtil;
import com.intellij.vcs.log.VcsLogSettings;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.ui.VcsLogUI;
import org.jetbrains.annotations.NotNull;
@@ -38,14 +40,19 @@ public class ActiveSurface extends JPanel implements TypeSafeDataProvider {
@NotNull private final Splitter myDetailsSplitter;
@NotNull private final JBLoadingPanel myChangesLoadingPane;
ActiveSurface(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI, @NotNull Project project) {
ActiveSurface(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI,
@NotNull VcsLogSettings settings, @NotNull Project project) {
myLogDataHolder = logDataHolder;
myGraphTable = new VcsLogGraphTable(vcsLogUI, logDataHolder);
myBranchesPanel = new BranchesPanel(logDataHolder, vcsLogUI);
if (!settings.isShowBranchesPanel()) {
myBranchesPanel.setVisible(false);
}
myDetailsPanel = new DetailsPanel(logDataHolder, myGraphTable, vcsLogUI.getColorManager());
final ChangesBrowser changesBrowser = new ChangesBrowser(project, null, Collections.<Change>emptyList(), null, false, false, null,
ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null);
final ChangesBrowser changesBrowser = new RepositoryChangesBrowser(project, null, Collections.<Change>emptyList(), null);
changesBrowser.getDiffAction().registerCustomShortcutSet(CommonShortcuts.getDiff(), myGraphTable);
setDefaultEmptyText(changesBrowser);
@@ -8,6 +8,7 @@ import com.intellij.ui.components.JBLoadingPanel;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.GridBag;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.Hash;
@@ -159,10 +160,12 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
else {
myHashLabel.setText(commit.getHash().toShortString());
myCommitMessage.setText(commit.getFullMessage());
myCommitMessage.setCaretPosition(0);
String authorText = commit.getAuthorName();
String authorText = commit.getAuthorName() + " at " + DateFormatUtil.formatDateTime(commit.getAuthorTime());
if (!commit.getAuthorName().equals(commit.getCommitterName()) || !commit.getAuthorEmail().equals(commit.getCommitterEmail())) {
authorText += " (committed by " + commit.getCommitterName() + ")";
authorText += " (committed by " + commit.getCommitterName() +
" at " + DateFormatUtil.formatDateTime(commit.getCommitTime()) + ")";
}
myAuthor.setText(authorText);
}
@@ -190,6 +193,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
void setRefs(@NotNull List<VcsRef> refs) {
myRefs = refs;
setVisible(!myRefs.isEmpty());
repaint();
}
}
@@ -8,6 +8,9 @@ import com.intellij.openapi.project.Project;
import com.intellij.ui.JBColor;
import com.intellij.ui.SeparatorComponent;
import com.intellij.ui.SeparatorOrientation;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.VcsLogDataKeys;
import com.intellij.vcs.log.VcsLogSettings;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.data.VcsLogUiProperties;
import com.intellij.vcs.log.ui.VcsLogUI;
@@ -22,24 +25,25 @@ import java.awt.*;
/**
* @author erokhins
*/
public class MainFrame {
public class MainFrame extends JPanel implements TypeSafeDataProvider {
@NotNull private final VcsLogDataHolder myLogDataHolder;
@NotNull private final VcsLogUI myUI;
@NotNull private final Project myProject;
@NotNull private final JPanel myMainPanel;
@NotNull private final ActiveSurface myActiveSurface;
@NotNull private final VcsLogUiProperties myUiProperties;
@NotNull private final VcsLog myLog;
@NotNull private final VcsLogFilterUi myFilterUi;
public MainFrame(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI, @NotNull Project project,
@NotNull VcsLogUiProperties uiProperties) {
@NotNull VcsLogSettings settings, @NotNull VcsLogUiProperties uiProperties, @NotNull VcsLog log) {
myLogDataHolder = logDataHolder;
myUI = vcsLogUI;
myProject = project;
myUiProperties = uiProperties;
myLog = log;
myActiveSurface = new ActiveSurface(logDataHolder, vcsLogUI, project);
myActiveSurface = new ActiveSurface(logDataHolder, vcsLogUI, settings, project);
myActiveSurface.setupDetailsSplitter(myUiProperties.isShowDetails());
JComponent toolbar = Box.createHorizontalBox();
@@ -48,10 +52,9 @@ public class MainFrame {
toolbar.add(new SeparatorComponent(JBColor.LIGHT_GRAY, SeparatorOrientation.VERTICAL));
toolbar.add(createActionsToolbar());
myMainPanel = new JPanel();
myMainPanel.setLayout(new BorderLayout());
myMainPanel.add(toolbar, BorderLayout.NORTH);
myMainPanel.add(myActiveSurface, BorderLayout.CENTER);
setLayout(new BorderLayout());
add(toolbar, BorderLayout.NORTH);
add(myActiveSurface, BorderLayout.CENTER);
}
public VcsLogGraphTable getGraphTable() {
@@ -119,7 +122,7 @@ public class MainFrame {
}
};
refreshAction.registerShortcutOn(myMainPanel);
refreshAction.registerShortcutOn(this);
DefaultActionGroup toolbarGroup = new DefaultActionGroup(hideBranchesAction, showBranchesAction, showFullPatchAction, refreshAction,
showDetailsAction);
@@ -128,11 +131,21 @@ public class MainFrame {
}
public JComponent getMainComponent() {
return myMainPanel;
return this;
}
public void refresh() {
myActiveSurface.getBranchesPanel().rebuild();
}
public void setBranchesPanelVisible(boolean visible) {
myActiveSurface.getBranchesPanel().setVisible(visible);
}
@Override
public void calcData(DataKey key, DataSink sink) {
if (VcsLogDataKeys.VSC_LOG == key) {
sink.put(key, myLog);
}
}
}
@@ -5,6 +5,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsShortCommitDetails;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,6 +36,9 @@ public abstract class AbstractVcsLogTableModel<T> extends AbstractTableModel {
@Nullable
protected abstract VcsShortCommitDetails getShortDetails(int rowIndex);
@Nullable
public abstract VcsFullCommitDetails getFullCommitDetails(int row);
@NotNull
@Override
public final Object getValueAt(int rowIndex, int columnIndex) {
@@ -54,6 +54,13 @@ public class GraphTableModel extends AbstractVcsLogTableModel<GraphCommitCell> {
return commitNode == null ? null : myDataHolder.getMiniDetailsGetter().getCommitData(commitNode);
}
@Nullable
@Override
public VcsFullCommitDetails getFullCommitDetails(int row) {
Node node = myDataPack.getGraphModel().getGraph().getCommitNodeInRow(row);
return node == null ? null : myDataHolder.getCommitDetailsGetter().getCommitData(node);
}
@Override
public void requestToLoadMore() {
myDataHolder.showFullLog(EmptyRunnable.INSTANCE);
@@ -41,6 +41,12 @@ public class NoGraphTableModel extends AbstractVcsLogTableModel<CommitCell> {
@Nullable
@Override
protected VcsShortCommitDetails getShortDetails(int rowIndex) {
return getFullCommitDetails(rowIndex);
}
@Nullable
@Override
public VcsFullCommitDetails getFullCommitDetails(int rowIndex) {
VcsFullCommitDetails commits = myCommits.get(rowIndex);
if (commits == null) {
LOG.error("Couldn't identify details for commit at " + rowIndex, new Attachment("loaded_commits", myCommits.toString()));
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.bugs;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.*;
@@ -146,6 +148,13 @@ public class IgnoreResultOfCallInspectionBase extends BaseInspection {
registerMethodCallError(call, aClass);
return;
}
PsiAnnotation contractAnnotation = ControlFlowAnalyzer.findContractAnnotation(method);
if (contractAnnotation != null && Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(contractAnnotation, "pure"))) {
registerMethodCallError(call, aClass);
return;
}
final PsiReferenceExpression methodExpression = call.getMethodExpression();
final String methodName = methodExpression.getReferenceName();
if (methodName == null) {
@@ -12,15 +12,15 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase {
@Override
protected String[] getEnvironmentClasses() {
return new String[]{
return [
"package java.util.regex; public class Pattern {" +
" public static Pattern compile(String regex) {return null;}" +
" public Matcher matcher(CharSequence input) {return null;}" +
"}",
"package java.util.regex; public class Matcher {" +
" public boolean find() {return true;}" +
"}",
};
"}"
] as String[]
}
public void testObjectMethods() {
@@ -41,4 +41,21 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase {
" }\n" +
"}\n");
}
public void testPureMethod() {
doTest """
import org.jetbrains.annotations.Contract;
class Util {
@Contract(pure=true)
static Object util() { return null; }
}
class C {
{
Util./*Result of 'Util.util()' is ignored*/util/**/();
}
}
"""
}
}
+19 -2
View File
@@ -75,10 +75,27 @@
<separator/>
</group>
<action id="Git.CherryPick" class="git4idea.cherrypick.GitCherryPickAction" text="Cherry-Pick" icon="Git4ideaIcons.CherryPick" anchor="First">
<action id="Git.CherryPick" class="git4idea.cherrypick.GitCherryPickAction" text="Cherry-Pick" icon="Git4ideaIcons.CherryPick"/>
<action class="git4idea.actions.GitCheckoutRevisionAction" id="Git.CheckoutRevision" text="Checkout Revision"/>
<action class="git4idea.actions.GitCreateNewBranchAction" id="Git.CreateNewBranch" text="New Branch"
description="Create new branch starting from the selected commit"/>
<action class="git4idea.actions.GitCreateTagAction" id="Git.CreateNewTag" text="New Tag"
description="Create new tag pointing to this commit"/>
<group id="Git.Log.ContextMenu">
<separator/>
<reference id="Git.CherryPick" />
<reference id="Git.CheckoutRevision"/>
<reference id="Git.CreateNewBranch" />
<reference id="Git.CreateNewTag" />
<add-to-group group-id="Vcs.Log.ContextMenu" />
</group>
<group id="Git.Log.Toolbar">
<reference id="Git.CherryPick"/>
<add-to-group group-id="Vcs.Log.Toolbar" />
</action>
</group>
</actions>
@@ -939,4 +939,16 @@ public class GitUtil {
final String output = diff.run();
return !output.trim().isEmpty();
}
/**
* Report a warning that the given root has no associated GitRepositories.
*/
public static void noRepositoryForRoot(@NotNull Logger log, @NotNull VirtualFile root, @NotNull Project project) {
GitRepositoryManager repositoryManager = getRepositoryManager(project);
ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
List<VirtualFile> roots = Arrays.asList(vcsManager.getRootsUnderVcs(GitVcs.getInstance(project)));
log.warn(String.format("Repository not found for root: %s. All roots: %s, all repositories: %s", root, roots,
repositoryManager.getRepositories()));
}
}
@@ -0,0 +1,34 @@
/*
* 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 git4idea.actions;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.vcs.log.VcsFullCommitDetails;
import git4idea.branch.GitBrancher;
import git4idea.repo.GitRepository;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
public class GitCheckoutRevisionAction extends GitLogSingleCommitAction {
@Override
protected void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit) {
GitBrancher brancher = ServiceManager.getService(repository.getProject(), GitBrancher.class);
brancher.checkout(commit.getHash().asString(), Collections.singletonList(repository), null);
}
}
@@ -0,0 +1,41 @@
/*
* 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 git4idea.actions;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.vcs.log.VcsFullCommitDetails;
import git4idea.branch.GitBranchUtil;
import git4idea.branch.GitBrancher;
import git4idea.repo.GitRepository;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
public class GitCreateNewBranchAction extends GitLogSingleCommitAction {
@Override
protected void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit) {
Project project = repository.getProject();
String reference = commit.getHash().asString();
final String name = GitBranchUtil.getNewBranchNameFromUser(project, Collections.singleton(repository),
"Checkout New Branch From " + reference);
if (name != null) {
GitBrancher brancher = ServiceManager.getService(project, GitBrancher.class);
brancher.checkoutNewBranchStartingFrom(name, reference, Collections.singletonList(repository), null);
}
}
}
@@ -0,0 +1,31 @@
/*
* 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 git4idea.actions;
import com.intellij.vcs.log.VcsFullCommitDetails;
import git4idea.history.wholeTree.GitCreateNewTag;
import git4idea.repo.GitRepository;
import org.jetbrains.annotations.NotNull;
public class GitCreateTagAction extends GitLogSingleCommitAction {
@Override
protected void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit) {
String reference = commit.getHash().asString();
new GitCreateNewTag(repository.getProject(), repository, reference, null).execute();
}
}
@@ -0,0 +1,90 @@
/*
* 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 git4idea.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.VcsLogDataKeys;
import git4idea.GitUtil;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author Kirill Likhodedov
*/
public abstract class GitLogSingleCommitAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(GitLogSingleCommitAction.class);
protected abstract void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit);
@Override
public void actionPerformed(AnActionEvent e) {
Data data = Data.collect(e);
if (!data.isValid()) {
return;
}
List<VcsFullCommitDetails> details = data.log.getSelectedDetails();
if (details.size() != 1) {
return;
}
VcsFullCommitDetails commit = details.get(0);
GitRepositoryManager repositoryManager = ServiceManager.getService(data.project, GitRepositoryManager.class);
final GitRepository repository = repositoryManager.getRepositoryForRoot(commit.getRoot());
if (repository == null) {
GitUtil.noRepositoryForRoot(LOG, commit.getRoot(), data.project);
return;
}
actionPerformed(repository, commit);
}
@Override
public void update(AnActionEvent e) {
Data data = Data.collect(e);
boolean enabled = data.isValid() && data.log.getSelectedCommits().size() == 1;
getTemplatePresentation().setVisible(data.isValid());
getTemplatePresentation().setEnabled(enabled);
}
private static class Data {
Project project;
VcsLog log;
static Data collect(AnActionEvent e) {
Data data = new Data();
data.project = e.getData(CommonDataKeys.PROJECT);
data.log = e.getData(VcsLogDataKeys.VSC_LOG);
return data;
}
boolean isValid() {
return project != null && log != null;
}
}
}
@@ -26,11 +26,7 @@ import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.VcsLogObjectsFactory;
import com.intellij.vcs.log.impl.VcsLogImpl;
import com.intellij.vcs.log.*;
import git4idea.GitLocalBranch;
import git4idea.GitPlatformFacade;
import git4idea.GitVcs;
@@ -175,7 +171,7 @@ public class GitCherryPickAction extends DumbAwareAction {
if (commits != null) {
return convertHeavyCommitToFullDetails(commits, project);
}
final VcsLog log = getVcsLog(project);
final VcsLog log = getVcsLog(e);
if (log == null) {
return null;
}
@@ -218,9 +214,8 @@ public class GitCherryPickAction extends DumbAwareAction {
});
}
private static VcsLog getVcsLog(@NotNull Project project) {
VcsLog logService = ServiceManager.getService(project, VcsLog.class);
return logService != null && ((VcsLogImpl)logService).isReady() ? logService : null;
private static VcsLog getVcsLog(@NotNull AnActionEvent event) {
return event.getData(VcsLogDataKeys.VSC_LOG);
}
// TODO remove after removing the old Vcs Log implementation
@@ -233,7 +228,7 @@ public class GitCherryPickAction extends DumbAwareAction {
if (event.getProject() == null) {
return null;
}
VcsLog log = getVcsLog(event.getProject());
VcsLog log = getVcsLog(event);
if (log == null) {
return null;
}
@@ -22,11 +22,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.VcsLogObjectsFactory;
import com.intellij.vcs.log.VcsShortCommitDetails;
import com.intellij.vcs.log.impl.VcsLogImpl;
import com.intellij.vcs.log.*;
import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.history.browser.GitHeavyCommit;
@@ -84,8 +80,8 @@ public class GithubShowCommitInBrowserFromLogAction extends GithubShowCommitInBr
return factory.createShortDetails(factory.createHash(heavyCommit.getHash().getValue()), parents, heavyCommit.getAuthorTime(),
heavyCommit.getRoot(), heavyCommit.getSubject(), heavyCommit.getAuthor());
}
VcsLog log = ServiceManager.getService(e.getProject(), VcsLog.class);
if (log == null || !((VcsLogImpl)log).isReady()) {
VcsLog log = e.getData(VcsLogDataKeys.VSC_LOG);
if (log == null) {
return null;
}
List<Hash> selectedCommits = log.getSelectedCommits();
@@ -15,6 +15,7 @@
*/
package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.io.*;
import gnu.trove.THashMap;
@@ -617,8 +618,13 @@ public class MavenIndex {
}
}
private PersistentHashMap<String, Set<String>> createPersistentMap(File f) throws IOException {
return new PersistentHashMap<String, Set<String>>(f, new EnumeratorStringDescriptor(), new SetDescriptor());
private PersistentHashMap<String, Set<String>> createPersistentMap(final File f) throws IOException {
return IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentHashMap<String, Set<String>>, IOException>() {
@Override
public PersistentHashMap<String, Set<String>> compute() throws IOException {
return new PersistentHashMap<String, Set<String>>(f, new EnumeratorStringDescriptor(), new SetDescriptor());
}
}, f);
}
public void close(boolean releaseIndexContext) throws MavenIndexException {