mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -177,9 +177,11 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
|
||||
else {
|
||||
previous = myModuleBytecodeTarget.put(module.getName(), level);
|
||||
}
|
||||
if (!Comparing.equal(previous, level)) {
|
||||
//final Project project = module.getProject(); // todo[jeka] so what?
|
||||
}
|
||||
// todo: mark module as dirty in order to rebuild it completely with the new target level
|
||||
//if (!Comparing.equal(previous, level)) {
|
||||
// final Project project = module.getProject();
|
||||
//
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -453,7 +453,6 @@ public class CompileDriver {
|
||||
return buildManager.scheduleBuild(myProject, compileContext.isRebuild(), compileContext.isMake(), moduleNames, artifactNames, paths, builderParams, new DefaultMessageHandler(myProject) {
|
||||
@Override
|
||||
public void sessionTerminated() {
|
||||
notifyCompilationCompleted(compileContext, callback, COMPILE_SERVER_BUILD_STATUS.get(compileContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -587,12 +586,16 @@ public class CompileDriver {
|
||||
}
|
||||
return;
|
||||
}
|
||||
final long start = System.currentTimeMillis();
|
||||
try {
|
||||
LOG.info("COMPILATION STARTED (BUILD PROCESS)");
|
||||
if (message != null) {
|
||||
compileContext.addMessage(message);
|
||||
}
|
||||
if (!executeCompileTasks(compileContext, true)) {
|
||||
COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED);
|
||||
return;
|
||||
}
|
||||
|
||||
final Collection<String> paths = fetchFiles(compileContext);
|
||||
final List<Module> modules = paths.isEmpty() && !isRebuild && !allProjectModulesAffected(compileContext)? Arrays.asList(compileContext.getCompileScope().getAffectedModules()) : Collections.<Module>emptyList();
|
||||
final Set<Artifact> artifacts = ArtifactCompileScope.getArtifactsToBuild(myProject, compileContext.getCompileScope(), true);
|
||||
@@ -603,33 +606,35 @@ public class CompileDriver {
|
||||
future.cancel(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
callback.finished(false, compileContext.getMessageCount(CompilerMessageCategory.ERROR), compileContext.getMessageCount(CompilerMessageCategory.WARNING), compileContext);
|
||||
if (!executeCompileTasks(compileContext, false)) {
|
||||
COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e); // todo
|
||||
callback.finished(false, compileContext.getMessageCount(CompilerMessageCategory.ERROR), compileContext.getMessageCount(CompilerMessageCategory.WARNING), compileContext);
|
||||
}
|
||||
finally {
|
||||
final long finish = System.currentTimeMillis();
|
||||
final long duration = notifyCompilationCompleted(compileContext, callback, COMPILE_SERVER_BUILD_STATUS.get(compileContext));
|
||||
CompilerUtil.logDuration(
|
||||
"\tCOMPILATION FINISHED (BUILD PROCESS); Errors: " +
|
||||
compileContext.getMessageCount(CompilerMessageCategory.ERROR) +
|
||||
"; warnings: " +
|
||||
compileContext.getMessageCount(CompilerMessageCategory.WARNING),
|
||||
finish - start
|
||||
duration
|
||||
);
|
||||
|
||||
CompilerCacheManager.getInstance(myProject).flushCaches();
|
||||
|
||||
// todo: need this for tests; should be removed later
|
||||
final Set<File> outputs = new HashSet<File>();
|
||||
for (final String path : CompilerPathsEx.getOutputPaths(ModuleManager.getInstance(myProject).getModules())) {
|
||||
outputs.add(new File(path));
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
// need this for tests only;
|
||||
final Set<File> outputs = new HashSet<File>();
|
||||
for (final String path : CompilerPathsEx.getOutputPaths(ModuleManager.getInstance(myProject).getModules())) {
|
||||
outputs.add(new File(path));
|
||||
}
|
||||
CompilerUtil.refreshIOFiles(outputs);
|
||||
}
|
||||
CompilerUtil.refreshIOFiles(outputs);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -643,7 +648,6 @@ public class CompileDriver {
|
||||
}
|
||||
return;
|
||||
}
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
if (myProject.isDisposed()) {
|
||||
return;
|
||||
@@ -656,14 +660,6 @@ public class CompileDriver {
|
||||
doCompile(compileContext, isRebuild, forceCompile, callback, checkCachesVersion);
|
||||
}
|
||||
finally {
|
||||
final long finish = System.currentTimeMillis();
|
||||
CompilerUtil.logDuration(
|
||||
"\tCOMPILATION FINISHED; Errors: " +
|
||||
compileContext.getMessageCount(CompilerMessageCategory.ERROR) +
|
||||
"; warnings: " +
|
||||
compileContext.getMessageCount(CompilerMessageCategory.WARNING),
|
||||
finish - start
|
||||
);
|
||||
CompilerCacheManager.getInstance(myProject).flushCaches();
|
||||
FileUtil.delete(CompilerPaths.getRebuildMarkerFile(myProject));
|
||||
}
|
||||
@@ -727,7 +723,7 @@ public class CompileDriver {
|
||||
final boolean checkCachesVersion) {
|
||||
ExitStatus status = ExitStatus.ERRORS;
|
||||
boolean wereExceptions = false;
|
||||
final long vfsTimestamp = ((PersistentFS)ManagingFS.getInstance()).getCreationTimestamp();
|
||||
final long vfsTimestamp = (ManagingFS.getInstance()).getCreationTimestamp();
|
||||
try {
|
||||
if (checkCachesVersion) {
|
||||
checkCachesVersion(compileContext, vfsTimestamp);
|
||||
@@ -765,7 +761,6 @@ public class CompileDriver {
|
||||
}
|
||||
finally {
|
||||
dropDependencyCache(compileContext);
|
||||
final ExitStatus _status = status;
|
||||
if (compileContext.isRebuildRequested()) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
@@ -778,13 +773,20 @@ public class CompileDriver {
|
||||
if (!myProject.isDisposed()) {
|
||||
writeStatus(new CompileStatus(CompilerConfigurationImpl.DEPENDENCY_FORMAT_VERSION, wereExceptions, vfsTimestamp), compileContext);
|
||||
}
|
||||
notifyCompilationCompleted(compileContext, callback, _status);
|
||||
final long duration = notifyCompilationCompleted(compileContext, callback, status);
|
||||
CompilerUtil.logDuration(
|
||||
"\tCOMPILATION FINISHED; Errors: " +
|
||||
compileContext.getMessageCount(CompilerMessageCategory.ERROR) +
|
||||
"; warnings: " +
|
||||
compileContext.getMessageCount(CompilerMessageCategory.WARNING),
|
||||
duration
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @noinspection SSBasedInspection*/
|
||||
private void notifyCompilationCompleted(final CompileContextImpl compileContext, final CompileStatusNotification callback, final ExitStatus _status) {
|
||||
private long notifyCompilationCompleted(final CompileContextImpl compileContext, final CompileStatusNotification callback, final ExitStatus _status) {
|
||||
final long duration = System.currentTimeMillis() - compileContext.getStartCompilationStamp();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
@@ -812,6 +814,7 @@ public class CompileDriver {
|
||||
}
|
||||
}
|
||||
});
|
||||
return duration;
|
||||
}
|
||||
|
||||
private void checkCachesVersion(final CompileContextImpl compileContext, final long currentVFSTimestamp) {
|
||||
|
||||
@@ -53,7 +53,10 @@ import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.SavingRequestor;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingManager;
|
||||
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
||||
@@ -276,6 +279,11 @@ public class BuildManager implements ApplicationComponent{
|
||||
}
|
||||
catch (RejectedExecutionException ignored) {
|
||||
// we were shut down
|
||||
myAutoMakeInProgress.set(false);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
myAutoMakeInProgress.set(false);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+20
-10
@@ -19,6 +19,7 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.ui.CollectionComboBoxModel;
|
||||
import com.intellij.ui.components.JBList;
|
||||
@@ -28,6 +29,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.List;
|
||||
@@ -76,11 +78,16 @@ public class BreakpointChooser {
|
||||
break;
|
||||
}
|
||||
}
|
||||
final Ref<Object> hackedSelection = Ref.create();
|
||||
|
||||
myDetailController = new DetailController(new MasterController() {
|
||||
JLabel fake = new JLabel();
|
||||
@Override
|
||||
public ItemWrapper[] getSelectedItems() {
|
||||
return new ItemWrapper[]{((BreakpointItem)myList.getSelectedValue())};
|
||||
if (hackedSelection.get() == null) {
|
||||
return new ItemWrapper[0];
|
||||
}
|
||||
return new ItemWrapper[]{((BreakpointItem) hackedSelection.get())};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,18 +99,21 @@ public class BreakpointChooser {
|
||||
final ItemWrapperListRenderer listRenderer = new ItemWrapperListRenderer(project, null);
|
||||
|
||||
ComboBoxModel model = new CollectionComboBoxModel(breakpointItems, breakpointItem);
|
||||
myComboBox = new ComboBox(model) {
|
||||
myComboBox = new ComboBox(model);
|
||||
myComboBox.setRenderer(new ItemWrapperListRenderer(project, null) {
|
||||
@Override
|
||||
protected JBList createJBList(ComboBoxModel model) {
|
||||
myList = super.createJBList(model);
|
||||
myDetailController.setList(myList);
|
||||
myList.setCellRenderer(listRenderer);
|
||||
return myList;
|
||||
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
|
||||
super.customizeCellRenderer(list, value, index, selected,
|
||||
hasFocus);
|
||||
if (selected) {
|
||||
if (hackedSelection.get() != value) {
|
||||
hackedSelection.set(value);
|
||||
myDetailController.selectionChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
myComboBox.setRenderer(listRenderer);
|
||||
});
|
||||
|
||||
myComboBox.setSwingPopup(false);
|
||||
myComboBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent event) {
|
||||
|
||||
+9
-12
@@ -863,22 +863,19 @@ public abstract class BreakpointPropertiesPanel {
|
||||
}
|
||||
|
||||
protected void updateCheckboxes() {
|
||||
JCheckBox [] checkBoxes = {myInstanceFiltersCheckBox, myClassFiltersCheckBox };
|
||||
JCheckBox selected = null;
|
||||
for (JCheckBox checkBoxe : checkBoxes) {
|
||||
if (checkBoxe.isSelected()) {
|
||||
selected = checkBoxe;
|
||||
JCheckBox [] checkBoxes = {myConditionCheckbox, myInstanceFiltersCheckBox, myClassFiltersCheckBox };
|
||||
boolean passCountApplicable = true;
|
||||
for (JCheckBox checkBox : checkBoxes) {
|
||||
if (checkBox.isSelected()) {
|
||||
passCountApplicable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(selected != null || !myConditionCheckbox.isSelected()){
|
||||
myPassCountCheckbox.setEnabled(false);
|
||||
} else {
|
||||
myPassCountCheckbox.setEnabled(true);
|
||||
}
|
||||
myPassCountCheckbox.setEnabled(passCountApplicable);
|
||||
|
||||
for (JCheckBox checkBoxe : checkBoxes) {
|
||||
checkBoxe.setEnabled(!myPassCountCheckbox.isSelected());
|
||||
final boolean passCountSelected = myPassCountCheckbox.isSelected();
|
||||
for (JCheckBox checkBox : checkBoxes) {
|
||||
checkBox.setEnabled(!passCountSelected);
|
||||
}
|
||||
|
||||
myPassCountField.setEditable(myPassCountCheckbox.isSelected());
|
||||
|
||||
@@ -88,6 +88,10 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
|
||||
}
|
||||
|
||||
PsiTypeLookupItem.addImportForItem(context, psiClass);
|
||||
if (context.getOffset(refEnd) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.setTailOffset(context.getOffset(refEnd));
|
||||
|
||||
if (shouldInsertParentheses(file.findElementAt(context.getTailOffset() - 1))) {
|
||||
|
||||
+1
@@ -356,6 +356,7 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
|
||||
|
||||
if (param.isValid()) {
|
||||
PsiType paramType = param.getType();
|
||||
assert paramType.isValid();
|
||||
if (substitutor != null) {
|
||||
paramType = substitutor.substitute(paramType);
|
||||
}
|
||||
|
||||
+6
-12
@@ -180,12 +180,9 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer
|
||||
@Override
|
||||
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
|
||||
final ElementManipulator<PsiElement> manipulator = getManipulator(getElement());
|
||||
if (manipulator != null) {
|
||||
final PsiElement element = manipulator.handleContentChange(getElement(), getRangeInElement(), newElementName);
|
||||
myRange = new TextRange(getRangeInElement().getStartOffset(), getRangeInElement().getStartOffset() + newElementName.length());
|
||||
return element;
|
||||
}
|
||||
throw new IncorrectOperationException("Manipulator for this element is not defined: " + getElement());
|
||||
final PsiElement element = manipulator.handleContentChange(getElement(), getRangeInElement(), newElementName);
|
||||
myRange = new TextRange(getRangeInElement().getStartOffset(), getRangeInElement().getStartOffset() + newElementName.length());
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -215,12 +212,9 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer
|
||||
}
|
||||
TextRange range = new TextRange(myJavaClassReferenceSet.getReference(0).getRangeInElement().getStartOffset(), end);
|
||||
final ElementManipulator<PsiElement> manipulator = getManipulator(getElement());
|
||||
if (manipulator != null) {
|
||||
final PsiElement finalElement = manipulator.handleContentChange(getElement(), range, newName);
|
||||
myJavaClassReferenceSet.reparse(finalElement, TextRange.from(range.getStartOffset(), newName.length()));
|
||||
return finalElement;
|
||||
}
|
||||
return element;
|
||||
final PsiElement finalElement = manipulator.handleContentChange(getElement(), range, newName);
|
||||
myJavaClassReferenceSet.reparse(finalElement, TextRange.from(range.getStartOffset(), newName.length()));
|
||||
return finalElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ public class MoveJavaClassHandler implements MoveClassHandler {
|
||||
newClass.getContainingFile().accept(new JavaRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
if (reference.isReferenceTo(oldClass)) {
|
||||
if (reference.isValid() && reference.isReferenceTo(oldClass)) {
|
||||
final PsiImportStatementBase importStatement = PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class);
|
||||
if (importStatement != null) {
|
||||
importsToDelete.add(importStatement);
|
||||
|
||||
@@ -233,25 +233,13 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
final List<PsiFile> files = myExternalAnnotations.get(fqn);
|
||||
if (files == NULL) return null;
|
||||
if (files != null) {
|
||||
boolean hasInvalidFiles = false;
|
||||
boolean allValid = true;
|
||||
for (PsiFile file : files) {
|
||||
if (!file.isValid()) {
|
||||
hasInvalidFiles = true;
|
||||
break;
|
||||
}
|
||||
allValid &= file.isValid();
|
||||
}
|
||||
if (hasInvalidFiles) {
|
||||
ArrayList<PsiFile> onlyValid = new ArrayList<PsiFile>();
|
||||
for (PsiFile file : files) {
|
||||
if (file.isValid()) {
|
||||
onlyValid.add(file);
|
||||
}
|
||||
}
|
||||
onlyValid.trimToSize();
|
||||
myExternalAnnotations.put(fqn, onlyValid);
|
||||
return onlyValid;
|
||||
if (allValid) {
|
||||
return files;
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
if (virtualFile == null) {
|
||||
|
||||
+17
-10
@@ -85,12 +85,14 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
|
||||
}
|
||||
|
||||
public int getKind() {
|
||||
IElementType i = getTreeParent().getElementType();
|
||||
LOG.assertTrue(isValid());
|
||||
CompositeElement treeParent = getTreeParent();
|
||||
IElementType i = treeParent.getElementType();
|
||||
if (isDummy(i)) {
|
||||
return myKindWhenDummy;
|
||||
}
|
||||
if (i == JavaElementType.TYPE) {
|
||||
return getTreeParent().getTreeParent().getPsi() instanceof PsiTypeCodeFragment ? CLASS_OR_PACKAGE_NAME_KIND : CLASS_NAME_KIND;
|
||||
return treeParent.getTreeParent().getPsi() instanceof PsiTypeCodeFragment ? CLASS_OR_PACKAGE_NAME_KIND : CLASS_NAME_KIND;
|
||||
}
|
||||
if (i == JavaElementType.EXTENDS_LIST ||
|
||||
i == JavaElementType.IMPLEMENTS_LIST ||
|
||||
@@ -108,13 +110,13 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
|
||||
return CLASS_NAME_KIND;
|
||||
}
|
||||
if (i == JavaElementType.NEW_EXPRESSION) {
|
||||
final ASTNode qualifier = getTreeParent().findChildByRole(ChildRole.QUALIFIER);
|
||||
final ASTNode qualifier = treeParent.findChildByRole(ChildRole.QUALIFIER);
|
||||
return qualifier != null ? CLASS_IN_QUALIFIED_NEW_KIND : CLASS_NAME_KIND;
|
||||
}
|
||||
if (i == JavaElementType.ANONYMOUS_CLASS) {
|
||||
if (getTreeParent().getChildRole(this) == ChildRole.BASE_CLASS_REFERENCE) {
|
||||
LOG.assertTrue(getTreeParent().getTreeParent().getElementType() == JavaElementType.NEW_EXPRESSION);
|
||||
final ASTNode qualifier = getTreeParent().getTreeParent().findChildByRole(ChildRole.QUALIFIER);
|
||||
if (treeParent.getChildRole(this) == ChildRole.BASE_CLASS_REFERENCE) {
|
||||
LOG.assertTrue(treeParent.getTreeParent().getElementType() == JavaElementType.NEW_EXPRESSION);
|
||||
final ASTNode qualifier = treeParent.getTreeParent().findChildByRole(ChildRole.QUALIFIER);
|
||||
return qualifier != null ? CLASS_IN_QUALIFIED_NEW_KIND : CLASS_NAME_KIND;
|
||||
}
|
||||
else {
|
||||
@@ -125,14 +127,14 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
|
||||
return PACKAGE_NAME_KIND;
|
||||
}
|
||||
if (i == JavaElementType.IMPORT_STATEMENT) {
|
||||
final boolean isOnDemand = ((PsiImportStatement)SourceTreeToPsiMap.treeElementToPsi(getTreeParent())).isOnDemand();
|
||||
final boolean isOnDemand = ((PsiImportStatement)SourceTreeToPsiMap.treeElementToPsi(treeParent)).isOnDemand();
|
||||
return isOnDemand ? CLASS_FQ_OR_PACKAGE_NAME_KIND : CLASS_FQ_NAME_KIND;
|
||||
}
|
||||
if (i == JavaElementType.IMPORT_STATIC_STATEMENT) {
|
||||
return CLASS_FQ_OR_PACKAGE_NAME_KIND;
|
||||
}
|
||||
if (i == JavaElementType.JAVA_CODE_REFERENCE) {
|
||||
final int parentKind = ((PsiJavaCodeReferenceElementImpl)getTreeParent()).getKind();
|
||||
final int parentKind = ((PsiJavaCodeReferenceElementImpl)treeParent).getKind();
|
||||
switch (parentKind) {
|
||||
case CLASS_NAME_KIND:
|
||||
return CLASS_OR_PACKAGE_NAME_KIND;
|
||||
@@ -170,11 +172,17 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
|
||||
return CLASS_OR_PACKAGE_NAME_KIND;
|
||||
}
|
||||
if (isCodeFragmentType(i)) {
|
||||
PsiJavaCodeReferenceCodeFragment fragment = (PsiJavaCodeReferenceCodeFragment)getTreeParent().getPsi();
|
||||
PsiJavaCodeReferenceCodeFragment fragment = (PsiJavaCodeReferenceCodeFragment)treeParent.getPsi();
|
||||
return fragment.isClassesAccepted() ? CLASS_FQ_OR_PACKAGE_NAME_KIND : PACKAGE_NAME_KIND;
|
||||
}
|
||||
|
||||
diagnoseUnknownParent();
|
||||
return CLASS_NAME_KIND;
|
||||
}
|
||||
|
||||
private void diagnoseUnknownParent() {
|
||||
CompositeElement parent = getTreeParent();
|
||||
IElementType i = parent.getElementType();
|
||||
String message = "Unknown parent for java code reference: '" + parent + "'; Type: " + i + ";\n";
|
||||
while (parent != null && parent.getPsi() instanceof PsiExpression) {
|
||||
parent = parent.getTreeParent();
|
||||
@@ -184,7 +192,6 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
|
||||
message += DebugUtil.treeToString(parent, false);
|
||||
}
|
||||
LOG.error(message);
|
||||
return CLASS_NAME_KIND;
|
||||
}
|
||||
|
||||
private static boolean isCodeFragmentType(IElementType type) {
|
||||
|
||||
+4
@@ -319,6 +319,10 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple
|
||||
LOG.error("getManager() == null!");
|
||||
return JavaResolveResult.EMPTY_ARRAY;
|
||||
}
|
||||
if (!isValid()) {
|
||||
LOG.error("invalid!");
|
||||
return JavaResolveResult.EMPTY_ARRAY;
|
||||
}
|
||||
ResolveResult[] results = ResolveCache.getInstance(getProject()).resolveWithCaching(this, OurGenericsResolver.INSTANCE, true, incompleteCode);
|
||||
return results.length == 0 ? JavaResolveResult.EMPTY_ARRAY : (JavaResolveResult[])results;
|
||||
}
|
||||
|
||||
+1
-2
@@ -5,7 +5,6 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
@@ -77,7 +76,7 @@ public abstract class CompletionSortingTestCase extends LightFixtureCompletionTe
|
||||
protected static void imitateItemSelection(final LookupImpl lookup, final int index) {
|
||||
final LookupElement item = lookup.getItems().get(index);
|
||||
lookup.setCurrentItem(item);
|
||||
CompletionLookupArranger.collectStatisticChanges(CompletionServiceImpl.getCompletionService().getCurrentCompletion(), item);
|
||||
CompletionLookupArranger.collectStatisticChanges(item, lookup);
|
||||
CompletionLookupArranger.applyLastCompletionStatisticsUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
*
|
||||
* @return the first child, or null if the element has no children.
|
||||
*/
|
||||
@Nullable
|
||||
PsiElement getFirstChild();
|
||||
|
||||
/**
|
||||
@@ -104,7 +103,6 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
*
|
||||
* @return the last child, or null if the element has no children.
|
||||
*/
|
||||
@Nullable
|
||||
PsiElement getLastChild();
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.openapi.editor.impl;
|
||||
import com.intellij.diagnostic.Dumpable;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.LocalTimeCounter;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
@@ -197,20 +198,20 @@ abstract class CharArray implements CharSequenceBackedByArray, Dumpable {
|
||||
assert count == stringLen || stringLen==-1;
|
||||
|
||||
if (!myDebug) return;
|
||||
final String stringFromCharArray;
|
||||
final CharSequence seqFromCharArray;
|
||||
|
||||
if (myArray != null) {
|
||||
assert myCount <= myArray.length;
|
||||
stringFromCharArray = new String(myArray, myStart, myCount);
|
||||
seqFromCharArray = new CharArrayCharSequence(myArray, myStart, myCount);
|
||||
} else {
|
||||
stringFromCharArray = null;
|
||||
seqFromCharArray = null;
|
||||
}
|
||||
|
||||
if (stringFromCharArray != null && originalSequence != null) {
|
||||
assert stringFromCharArray.equals(originalSequence);
|
||||
if (seqFromCharArray != null && originalSequence != null) {
|
||||
assert StringUtil.equals(seqFromCharArray, originalSequence);
|
||||
}
|
||||
if (!isDeferredChangeMode() && stringFromCharArray != null && string != null) {
|
||||
assert stringFromCharArray.equals(string);
|
||||
if (!isDeferredChangeMode() && seqFromCharArray != null && string != null) {
|
||||
assert StringUtil.equals(seqFromCharArray, string);
|
||||
}
|
||||
if (originalSequence != null && string != null) {
|
||||
assert string.equals(originalSequence.toString());
|
||||
@@ -218,7 +219,7 @@ abstract class CharArray implements CharSequenceBackedByArray, Dumpable {
|
||||
|
||||
myDebugArray.assertConsistency();
|
||||
|
||||
String str = myStringRef == null ? null : myStringRef.get();
|
||||
CharSequence str = myStringRef == null ? null : myStringRef.get();
|
||||
if (str == null) {
|
||||
if (myHasDeferredChanges) {
|
||||
str = doSubString(0, myCount + myDeferredShift).toString();
|
||||
@@ -227,7 +228,7 @@ abstract class CharArray implements CharSequenceBackedByArray, Dumpable {
|
||||
str = myOriginalSequence.toString();
|
||||
}
|
||||
else {
|
||||
str = stringFromCharArray;
|
||||
str = seqFromCharArray;
|
||||
}
|
||||
}
|
||||
assert count == str.length();
|
||||
@@ -675,8 +676,8 @@ abstract class CharArray implements CharSequenceBackedByArray, Dumpable {
|
||||
", deferred shift: " + myDeferredShift+"); view offsets: [" + myStart+"; "+myCount+"]; deferred changes: "+myDeferredChangesStorage;
|
||||
}
|
||||
|
||||
private void checkStrings(@NonNls @NotNull String operation, @NotNull String expected, @NotNull String actual) {
|
||||
if (expected.equals(actual)) {
|
||||
private void checkStrings(@NonNls @NotNull String operation, @NotNull String expected, @NotNull CharSequence actual) {
|
||||
if (StringUtil.equals(expected, actual)) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0, max = Math.min(expected.length(), actual.length()); i < max; i++) {
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
package com.intellij.execution.filters;
|
||||
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
* @since 7.0.3
|
||||
*/
|
||||
public interface FileHyperlinkInfo extends HyperlinkInfo {
|
||||
@Nullable
|
||||
OpenFileDescriptor getDescriptor();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,10 @@ public final class OpenFileHyperlinkInfo implements FileHyperlinkInfo {
|
||||
}
|
||||
|
||||
public OpenFileDescriptor getDescriptor() {
|
||||
if (!myFile.isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int offset = calculateOffset(myFile, myDocumentLine, myDocumentColumn);
|
||||
if (offset != UNDEFINED_OFFSET) {
|
||||
return new OpenFileDescriptor(myProject, myFile, offset);
|
||||
|
||||
+21
-12
@@ -113,15 +113,9 @@ public class CodeCompletionHandlerBase {
|
||||
final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
|
||||
assert psiFile != null : "no PSI file: " + FileDocumentManager.getInstance().getFile(editor.getDocument());
|
||||
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
throw new AssertionError("Completion should not be invoked inside write action");
|
||||
}
|
||||
}
|
||||
checkNoWriteAccess();
|
||||
|
||||
if (editor instanceof EditorWindow && !((EditorWindow)editor).isValid()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
checkEditorValid(editor);
|
||||
|
||||
if (editor.isViewer()) {
|
||||
editor.getDocument().fireReadOnlyModificationAttempt();
|
||||
@@ -191,9 +185,7 @@ public class CodeCompletionHandlerBase {
|
||||
throw new AssertionError("unsuccessful commit: injected=" + (editor instanceof EditorWindow));
|
||||
}
|
||||
|
||||
if (editor instanceof EditorWindow && !((EditorWindow)editor).isValid()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
checkEditorValid(editor);
|
||||
|
||||
final Ref<CompletionContributor> current = Ref.create(null);
|
||||
initializationContext[0] = new CompletionInitializationContext(editor, psiFile, myCompletionType) {
|
||||
@@ -215,6 +207,7 @@ public class CodeCompletionHandlerBase {
|
||||
|
||||
current.set(contributor);
|
||||
contributor.beforeCompletion(initializationContext[0]);
|
||||
checkEditorValid(editor);
|
||||
assert !documentManager.isUncommited(document) : "Contributor " + contributor + " left the document uncommitted";
|
||||
}
|
||||
}
|
||||
@@ -234,6 +227,20 @@ public class CodeCompletionHandlerBase {
|
||||
insertDummyIdentifier(initializationContext[0], hasModifiers, time);
|
||||
}
|
||||
|
||||
private static void checkEditorValid(Editor editor) {
|
||||
if (editor instanceof EditorWindow && !((EditorWindow)editor).isValid()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkNoWriteAccess() {
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
throw new AssertionError("Completion should not be invoked inside write action");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldSkipAutoPopup(Editor editor, PsiFile psiFile) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
int psiOffset = Math.max(0, offset - 1);
|
||||
@@ -260,6 +267,7 @@ public class CodeCompletionHandlerBase {
|
||||
|
||||
@NotNull
|
||||
private LookupImpl obtainLookup(Editor editor) {
|
||||
checkEditorValid(editor);
|
||||
LookupImpl existing = (LookupImpl)LookupManager.getActiveLookup(editor);
|
||||
if (existing != null && existing.isCompletion()) {
|
||||
existing.markReused();
|
||||
@@ -593,7 +601,8 @@ public class CodeCompletionHandlerBase {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_BASIC);
|
||||
}
|
||||
|
||||
final CompletionLookupArranger.StatisticsUpdate update = CompletionLookupArranger.collectStatisticChanges(indicator, item);
|
||||
final CompletionLookupArranger.StatisticsUpdate update =
|
||||
CompletionLookupArranger.collectStatisticChanges(item, indicator.getParameters().getLookup());
|
||||
|
||||
final Editor editor = indicator.getEditor();
|
||||
|
||||
|
||||
+35
-27
@@ -26,6 +26,7 @@ import com.intellij.featureStatistics.FeatureUsageTrackerImpl;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
@@ -48,6 +49,7 @@ import javax.swing.*;
|
||||
import java.util.*;
|
||||
|
||||
public class CompletionLookupArranger extends LookupArranger {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.CompletionLookupArranger");
|
||||
@Nullable private static StatisticsUpdate ourPendingUpdate;
|
||||
private static final Alarm ourStatsAlarm = new Alarm(ApplicationManager.getApplication());
|
||||
private static final Key<String> PRESENTATION_INVARIANT = Key.create("PRESENTATION_INVARIANT");
|
||||
@@ -136,7 +138,11 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
|
||||
@Override
|
||||
public void addElement(Lookup lookup, LookupElement element, LookupElementPresentation presentation) {
|
||||
super.addElement(lookup, element, presentation);
|
||||
StatisticsWeigher.clearBaseStatisticsInfo(element);
|
||||
|
||||
final String invariant = presentation.getItemText() + "###" + getTailTextOrSpace(presentation) + "###" + presentation.getTypeText();
|
||||
element.putUserData(PRESENTATION_INVARIANT, invariant);
|
||||
|
||||
CompletionSorterImpl sorter = obtainSorter(element);
|
||||
Classifier<LookupElement> classifier = myClassifiers.get(sorter);
|
||||
if (classifier == null) {
|
||||
@@ -144,8 +150,7 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
}
|
||||
classifier.addElement(element);
|
||||
|
||||
final String invariant = presentation.getItemText() + "###" + getTailTextOrSpace(presentation) + "###" + presentation.getTypeText();
|
||||
element.putUserData(PRESENTATION_INVARIANT, invariant);
|
||||
super.addElement(lookup, element, presentation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -175,11 +180,13 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
List<LookupElement> items = getMatchingItems();
|
||||
MultiMap<CompletionSorterImpl, LookupElement> itemsBySorter = groupItemsBySorter(items);
|
||||
|
||||
LookupElement relevantSelection = findMostRelevantItem(itemsBySorter);
|
||||
List<LookupElement> listModel = isAlphaSorted() ?
|
||||
sortByPresentation(items) :
|
||||
fillModelByRelevance((LookupImpl)lookup, items, itemsBySorter);
|
||||
fillModelByRelevance((LookupImpl)lookup, items, itemsBySorter, relevantSelection);
|
||||
|
||||
int toSelect = getItemToSelect(lookup, listModel, itemsBySorter, onExplicitAction);
|
||||
int toSelect = getItemToSelect(lookup, listModel, onExplicitAction, relevantSelection);
|
||||
LOG.assertTrue(toSelect >= 0);
|
||||
|
||||
addDummyItems(items.size() - listModel.size(), listModel);
|
||||
|
||||
@@ -195,7 +202,8 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
|
||||
private List<LookupElement> fillModelByRelevance(LookupImpl lookup,
|
||||
List<LookupElement> items,
|
||||
MultiMap<CompletionSorterImpl, LookupElement> inputBySorter) {
|
||||
MultiMap<CompletionSorterImpl, LookupElement> inputBySorter,
|
||||
@Nullable LookupElement relevantSelection) {
|
||||
Iterator<LookupElement> byRelevance = sortByRelevance(inputBySorter).iterator();
|
||||
|
||||
final LinkedHashSet<LookupElement> model = new LinkedHashSet<LookupElement>();
|
||||
@@ -212,7 +220,8 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
|
||||
freezeTopItems(lookup, model);
|
||||
|
||||
ensureCurrentSelectionAdded(lookup, items, model, byRelevance);
|
||||
ensureItemAdded(items, model, byRelevance, lookup.getCurrentItem());
|
||||
ensureItemAdded(items, model, byRelevance, relevantSelection);
|
||||
ensureEverythingVisibleAdded(lookup, model, byRelevance);
|
||||
|
||||
return new ArrayList<LookupElement>(model);
|
||||
@@ -230,16 +239,14 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
});
|
||||
}
|
||||
|
||||
private static void ensureCurrentSelectionAdded(LookupImpl lookup,
|
||||
List<LookupElement> items,
|
||||
LinkedHashSet<LookupElement> model,
|
||||
Iterator<LookupElement> byRelevance) {
|
||||
final LookupElement currentItem = lookup.getCurrentItem();
|
||||
if (ContainerUtil.indexOfIdentity(items, currentItem) >= 0 && !model.contains(currentItem)) {
|
||||
private static void ensureItemAdded(List<LookupElement> items,
|
||||
LinkedHashSet<LookupElement> model,
|
||||
Iterator<LookupElement> byRelevance, @Nullable final LookupElement item) {
|
||||
if (item != null && ContainerUtil.indexOfIdentity(items, item) >= 0 && !model.contains(item)) {
|
||||
addSomeItems(model, byRelevance, new Condition<LookupElement>() {
|
||||
@Override
|
||||
public boolean value(LookupElement lastAdded) {
|
||||
return lastAdded == currentItem;
|
||||
return lastAdded == item;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -306,9 +313,7 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
return new CompletionLookupArranger(myParameters, myProcess);
|
||||
}
|
||||
|
||||
private int getItemToSelect(Lookup lookup, List<LookupElement> items,
|
||||
MultiMap<CompletionSorterImpl, LookupElement> itemsBySorter,
|
||||
boolean onExplicitAction) {
|
||||
private static int getItemToSelect(Lookup lookup, List<LookupElement> items, boolean onExplicitAction, @Nullable LookupElement mostRelevant) {
|
||||
if (items.isEmpty() || !lookup.isFocused()) {
|
||||
return 0;
|
||||
}
|
||||
@@ -345,35 +350,38 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
}
|
||||
}
|
||||
|
||||
return Math.max(0, ContainerUtil.indexOfIdentity(items, mostRelevant));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LookupElement findMostRelevantItem(MultiMap<CompletionSorterImpl, LookupElement> itemsBySorter) {
|
||||
final CompletionPreselectSkipper[] skippers = CompletionPreselectSkipper.EP_NAME.getExtensions();
|
||||
for (CompletionSorterImpl sorter : myClassifiers.keySet()) {
|
||||
ProcessingContext context = createContext(true);
|
||||
for (LookupElement element : myClassifiers.get(sorter).classify(itemsBySorter.get(sorter), context)) {
|
||||
if (!shouldSkip(skippers, element)) {
|
||||
return items.indexOf(element);
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isLiveTemplate(LookupElement element) {
|
||||
return element instanceof LiveTemplateLookupElement && ((LiveTemplateLookupElement)element).sudden;
|
||||
}
|
||||
|
||||
public static StatisticsUpdate collectStatisticChanges(CompletionProgressIndicator indicator, LookupElement item) {
|
||||
public static StatisticsUpdate collectStatisticChanges(LookupElement item, final Lookup lookup) {
|
||||
applyLastCompletionStatisticsUpdate();
|
||||
|
||||
CompletionLocation location = new CompletionLocation(indicator.getParameters());
|
||||
final StatisticsInfo main = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, item, location);
|
||||
|
||||
final List<StatisticsInfo> toIncrement = new ArrayList<StatisticsInfo>();
|
||||
if (main != null && main != StatisticsInfo.EMPTY) {
|
||||
toIncrement.addAll(StatisticsWeigher.composeStatsWithPrefix(main, location, item));
|
||||
final StatisticsInfo base = StatisticsWeigher.getBaseStatisticsInfo(item, null);
|
||||
if (base == StatisticsInfo.EMPTY) {
|
||||
return new StatisticsUpdate(Collections.<StatisticsInfo>emptyList());
|
||||
}
|
||||
|
||||
StatisticsUpdate update = new StatisticsUpdate(toIncrement);
|
||||
StatisticsUpdate update = new StatisticsUpdate(StatisticsWeigher.composeStatsWithPrefix(base, lookup.itemPattern(item)));
|
||||
ourPendingUpdate = update;
|
||||
Disposer.register(update, new Disposable() {
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.statistics.StatisticsInfo;
|
||||
import com.intellij.psi.statistics.StatisticsManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -32,14 +33,14 @@ import java.util.List;
|
||||
*/
|
||||
public class StatisticsWeigher extends CompletionWeigher {
|
||||
private static final StatisticsManager ourStatManager = StatisticsManager.getInstance();
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.StatisticsWeigher.LookupStatisticsWeigher");
|
||||
private static final Key<StatisticsInfo> BASE_STATISTICS_INFO = Key.create("Base statistics info");
|
||||
|
||||
public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static class LookupStatisticsWeigher extends LookupElementWeigher {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.StatisticsWeigher.LookupStatisticsWeigher");
|
||||
private static final Key<StatisticsInfo> BASE_INFO = Key.create("Base statistics info");
|
||||
private final CompletionLocation myLocation;
|
||||
|
||||
public LookupStatisticsWeigher(CompletionLocation location) {
|
||||
@@ -49,38 +50,45 @@ public class StatisticsWeigher extends CompletionWeigher {
|
||||
|
||||
@Override
|
||||
public Integer weigh(@NotNull LookupElement item) {
|
||||
final StatisticsInfo info = getBaseStatisticsInfo(item);
|
||||
final StatisticsInfo info = getBaseStatisticsInfo(item, myLocation);
|
||||
if (info == StatisticsInfo.EMPTY) {
|
||||
return 0;
|
||||
}
|
||||
int max = 0;
|
||||
for (StatisticsInfo statisticsInfo : composeStatsWithPrefix(info, myLocation, item)) {
|
||||
for (StatisticsInfo statisticsInfo : composeStatsWithPrefix(info, myLocation.getCompletionParameters().getLookup().itemPattern(item))) {
|
||||
max = Math.max(max, ourStatManager.getUseCount(statisticsInfo));
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StatisticsInfo getBaseStatisticsInfo(LookupElement item) {
|
||||
StatisticsInfo info = BASE_INFO.get(item);
|
||||
if (info == null) {
|
||||
BASE_INFO.set(item, info = calcBaseInfo(item));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StatisticsInfo calcBaseInfo(LookupElement item) {
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isDispatchThread());
|
||||
}
|
||||
StatisticsInfo info = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, item, myLocation);
|
||||
return info == null ? StatisticsInfo.EMPTY : info;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<StatisticsInfo> composeStatsWithPrefix(StatisticsInfo info, CompletionLocation location, LookupElement item) {
|
||||
String fullPrefix = location.getCompletionParameters().getLookup().itemPattern(item);
|
||||
public static void clearBaseStatisticsInfo(LookupElement item) {
|
||||
item.putUserData(BASE_STATISTICS_INFO, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StatisticsInfo getBaseStatisticsInfo(LookupElement item, @Nullable CompletionLocation location) {
|
||||
StatisticsInfo info = BASE_STATISTICS_INFO.get(item);
|
||||
if (info == null) {
|
||||
if (location == null) {
|
||||
return StatisticsInfo.EMPTY;
|
||||
}
|
||||
BASE_STATISTICS_INFO.set(item, info = calcBaseInfo(item, location));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static StatisticsInfo calcBaseInfo(LookupElement item, @NotNull CompletionLocation location) {
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isDispatchThread());
|
||||
}
|
||||
StatisticsInfo info = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, item, location);
|
||||
return info == null ? StatisticsInfo.EMPTY : info;
|
||||
}
|
||||
|
||||
public static List<StatisticsInfo> composeStatsWithPrefix(StatisticsInfo info, final String fullPrefix) {
|
||||
ArrayList<StatisticsInfo> infos = new ArrayList<StatisticsInfo>(fullPrefix.length() + 1);
|
||||
infos.add(info);
|
||||
for (int i = 1; i <= fullPrefix.length(); i++) {
|
||||
|
||||
@@ -108,8 +108,8 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable
|
||||
@Override
|
||||
public void run() {
|
||||
EditorMarkupModel markupModel = (EditorMarkupModel)editor.getMarkupModel();
|
||||
PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
|
||||
TrafficLightRenderer.setOrRefreshErrorStripeRenderer(markupModel, myProject, document, file);
|
||||
PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument());
|
||||
TrafficLightRenderer.setOrRefreshErrorStripeRenderer(markupModel, myProject, editor.getDocument(), file);
|
||||
}
|
||||
}, ModalityState.stateForComponent(editor.getComponent()), myProject.getDisposed());
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.ui.LayeredIcon;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
|
||||
+4
@@ -44,6 +44,10 @@ public class SpaceHandler extends TypedActionHandlerBase {
|
||||
}
|
||||
|
||||
TemplateManagerImpl templateManager = (TemplateManagerImpl)TemplateManager.getInstance(project);
|
||||
if (templateManager == null) {
|
||||
throw new AssertionError(project + "; " + project.isDisposed());
|
||||
}
|
||||
|
||||
if (!templateManager.startTemplate(editor, TemplateSettings.SPACE_CHAR)) {
|
||||
if (myOriginalHandler != null) myOriginalHandler.execute(editor, charTyped, dataContext);
|
||||
}
|
||||
|
||||
+84
-17
@@ -17,6 +17,7 @@ package com.intellij.execution.console;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.execution.process.ConsoleHistoryModel;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
@@ -26,17 +27,26 @@ import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.command.undo.UndoConstants;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.actions.ContentChooser;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ex.ProjectEx;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.CharFilter;
|
||||
import com.intellij.openapi.util.text.StringHash;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.SafeFileOutputStream;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.xml.XppReader;
|
||||
@@ -218,9 +228,12 @@ public class ConsoleHistoryController {
|
||||
private static void cleanupOldFiles(final File dir) {
|
||||
final long keep2weeks = 2 * 1000L * 60 * 60 * 24 * 7;
|
||||
final long curTime = System.currentTimeMillis();
|
||||
for (File file : dir.listFiles()) {
|
||||
if (file.isFile() && file.getName().endsWith(".hist.xml") && curTime - file.lastModified() > keep2weeks) {
|
||||
file.delete();
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isFile() && file.getName().endsWith(".hist.xml") && curTime - file.lastModified() > keep2weeks) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,19 +259,46 @@ public class ConsoleHistoryController {
|
||||
if (storeUserText) {
|
||||
myUserValue = document.getText();
|
||||
}
|
||||
String text = StringUtil.notNullize(command);
|
||||
int offset;
|
||||
if (regularMode) {
|
||||
document.setText(StringUtil.notNullize(command));
|
||||
if (myMultiline) {
|
||||
if (text.isEmpty()) return;
|
||||
int selectionStart = editor.getSelectionModel().getSelectionStart();
|
||||
int selectionEnd = editor.getSelectionModel().getSelectionEnd();
|
||||
int caretOffset = editor.getCaretModel().getOffset();
|
||||
int line = document.getLineNumber(caretOffset);
|
||||
int lineStartOffset = document.getLineStartOffset(line);
|
||||
if (selectionStart == lineStartOffset) document.deleteString(selectionStart, selectionEnd);
|
||||
String trimmedLine = document.getText(new TextRange(lineStartOffset, document.getLineEndOffset(line))).trim();
|
||||
if (StringUtil.findFirst(trimmedLine, new CharFilter() {
|
||||
@Override
|
||||
public boolean accept(char ch) {
|
||||
return ch =='\'' || ch == '\"' || ch == '_' || Character.isLetterOrDigit(ch);
|
||||
}
|
||||
}) > -1) {
|
||||
text += "\n";
|
||||
}
|
||||
document.insertString(lineStartOffset, text);
|
||||
offset = lineStartOffset;
|
||||
editor.getSelectionModel().setSelection(lineStartOffset, lineStartOffset + text.length());
|
||||
}
|
||||
else {
|
||||
document.setText(text);
|
||||
offset = document.getTextLength();
|
||||
}
|
||||
}
|
||||
else {
|
||||
offset = 0;
|
||||
try {
|
||||
document.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
|
||||
document.setText(StringUtil.notNullize(command));
|
||||
document.setText(text);
|
||||
}
|
||||
finally {
|
||||
document.putUserData(UndoConstants.DONT_RECORD_UNDO, null);
|
||||
}
|
||||
}
|
||||
editor.getCaretModel().moveToOffset(regularMode? document.getTextLength() : 0);
|
||||
editor.getCaretModel().moveToOffset(offset);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
}.execute();
|
||||
@@ -276,15 +316,14 @@ public class ConsoleHistoryController {
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final String command;
|
||||
command = myNext ? myModel.getHistoryNext() : StringUtil.notNullize(myModel.getHistoryPrev(), StringUtil.notNullize(myUserValue));
|
||||
command = myNext ? myModel.getHistoryNext() : StringUtil.notNullize(myModel.getHistoryPrev(), myMultiline? "" : StringUtil.notNullize(myUserValue));
|
||||
setConsoleText(command, myNext && myModel.getHistoryCursor() == 0, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final AnActionEvent e) {
|
||||
super.update(e);
|
||||
final boolean hasStuff = myModel.hasHistory(myNext);
|
||||
e.getPresentation().setEnabled(hasStuff && (myMultiline || canMoveInEditor(myNext)));
|
||||
e.getPresentation().setEnabled(myMultiline || canMoveInEditor(myNext));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,23 +397,51 @@ public class ConsoleHistoryController {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final ContentChooser<String> chooser = new ContentChooser<String>(myConsole.getProject(), myConsole.getTitle(), true) {
|
||||
final ContentChooser<String> chooser = new ContentChooser<String>(myConsole.getProject(), myConsole.getTitle() + " History", true) {
|
||||
|
||||
@Override
|
||||
protected void removeContentAt(final String content) {
|
||||
protected void removeContentAt(String content) {
|
||||
myModel.removeFromHistory(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringRepresentationFor(final String content) {
|
||||
protected String getStringRepresentationFor(String content) {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getContents() {
|
||||
return myModel.getHistory();
|
||||
List<String> history = myModel.getHistory();
|
||||
return ContainerUtil.reverse(history);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Editor createIdeaEditor(String text) {
|
||||
PsiFile consoleFile = myConsole.getFile();
|
||||
Language language = consoleFile.getLanguage();
|
||||
Project project = consoleFile.getProject();
|
||||
|
||||
PsiFile psiFile = PsiFileFactory.getInstance(project).createFileFromText(
|
||||
"a."+consoleFile.getFileType().getDefaultExtension(),
|
||||
language,
|
||||
StringUtil.convertLineSeparators(new String(text)), false, true);
|
||||
VirtualFile virtualFile = psiFile.getViewProvider().getVirtualFile();
|
||||
if (virtualFile instanceof LightVirtualFile) ((LightVirtualFile)virtualFile).setWritable(false);
|
||||
Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
|
||||
EditorFactory editorFactory = EditorFactory.getInstance();
|
||||
EditorEx editor = (EditorEx)editorFactory.createViewer(document, project);
|
||||
editor.getSettings().setFoldingOutlineShown(false);
|
||||
editor.getSettings().setLineMarkerAreaShown(false);
|
||||
editor.getSettings().setIndentGuidesShown(false);
|
||||
|
||||
SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(language, project, psiFile.getViewProvider().getVirtualFile());
|
||||
editor.setHighlighter(new LexerEditorHighlighter(highlighter, editor.getColorsScheme()));
|
||||
return editor;
|
||||
}
|
||||
};
|
||||
chooser.setContentIcon(null);
|
||||
chooser.setSplitterOrientation(false);
|
||||
chooser.setSelectedIndex(Math.min(myModel.getHistorySize() - myModel.getHistoryCursor() - 1, myModel.getHistorySize() - 1));
|
||||
chooser.show();
|
||||
if (chooser.isOK()) {
|
||||
setConsoleText(myModel.getHistory().get(chooser.getSelectedIndex()), false, true);
|
||||
|
||||
@@ -1356,11 +1356,16 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
|
||||
@Nullable
|
||||
protected OccurenceInfo calcNextOccurrence(final int delta) {
|
||||
return EditorHyperlinkSupport.getNextOccurrence(myEditor, myHyperlinks.getHyperlinks().keySet(), delta, new Consumer<RangeHighlighter>() {
|
||||
final EditorHyperlinkSupport hyperlinks = myHyperlinks;
|
||||
if (hyperlinks == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return EditorHyperlinkSupport.getNextOccurrence(myEditor, hyperlinks.getHyperlinks().keySet(), delta, new Consumer<RangeHighlighter>() {
|
||||
@Override
|
||||
public void consume(RangeHighlighter next) {
|
||||
scrollTo(next.getStartOffset());
|
||||
final HyperlinkInfo hyperlinkInfo = myHyperlinks.getHyperlinks().get(next);
|
||||
final HyperlinkInfo hyperlinkInfo = hyperlinks.getHyperlinks().get(next);
|
||||
if (hyperlinkInfo != null) {
|
||||
hyperlinkInfo.navigate(myProject);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.concurrency.FutureResult;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
@@ -192,45 +193,6 @@ public class SearchResults implements DocumentListener {
|
||||
public void clear() {
|
||||
searchCompleted(new ArrayList<LiveOccurrence>(), getEditor(), null, false, null, getStamp());
|
||||
}
|
||||
|
||||
private static class BombedCharSequence implements CharSequence {
|
||||
private CharSequence delegate;
|
||||
private long myTime;
|
||||
private long i = 0;
|
||||
|
||||
public BombedCharSequence(CharSequence sequence, long time) {
|
||||
delegate = sequence;
|
||||
myTime = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
check();
|
||||
return delegate.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int i) {
|
||||
check();
|
||||
return delegate.charAt(i);
|
||||
}
|
||||
|
||||
private void check() {
|
||||
++i;
|
||||
if (i % 1000 == 0) {
|
||||
long l = System.currentTimeMillis();
|
||||
if (l >= myTime) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int i, int i1) {
|
||||
check();
|
||||
return delegate.subSequence(i, i1);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateThreadSafe(final FindModel findModel, final boolean toChangeSelection, @Nullable final TextRange next, final int stamp) {
|
||||
if (myDisposed) return;
|
||||
@@ -330,8 +292,8 @@ public class SearchResults implements DocumentListener {
|
||||
FindManager findManager = FindManager.getInstance(getProject());
|
||||
FindResult result;
|
||||
try {
|
||||
BombedCharSequence
|
||||
bombedCharSequence = new BombedCharSequence(editor.getDocument().getCharsSequence(), System.currentTimeMillis() + 3000);
|
||||
StringUtil.BombedCharSequence
|
||||
bombedCharSequence = new StringUtil.BombedCharSequence(editor.getDocument().getCharsSequence(), System.currentTimeMillis() + 3000);
|
||||
result = findManager.findString(bombedCharSequence, offset, findModel, virtualFile);
|
||||
} catch(PatternSyntaxException e) {
|
||||
result = null;
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.PlatformUtils;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
@@ -327,7 +328,7 @@ public class MemberChooser<T extends ClassMember> extends DialogWrapper implemen
|
||||
String text = lastPathComponent.getDelegate().getText();
|
||||
if (text != null) {
|
||||
int i = text.indexOf(':');
|
||||
if (i >= 0) {
|
||||
if (i >= 0 && !PlatformUtils.isCidr()) { // In AppCode colons can occur in the method selectors and matching should work after them
|
||||
text = text.substring(0, i);
|
||||
}
|
||||
i = text.indexOf('(');
|
||||
|
||||
@@ -53,10 +53,7 @@ import com.intellij.psi.codeStyle.NameUtil;
|
||||
import com.intellij.psi.statistics.StatisticsInfo;
|
||||
import com.intellij.psi.statistics.StatisticsManager;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.ClickListener;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.ListScrollingUtil;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.popup.PopupOwner;
|
||||
import com.intellij.ui.popup.PopupPositionManager;
|
||||
@@ -1416,12 +1413,18 @@ public abstract class ChooseByNameBase {
|
||||
public static final String NON_PREFIX_SEPARATOR = "non-prefix matches:";
|
||||
|
||||
public static Component renderNonPrefixSeparatorComponent(Color backgroundColor) {
|
||||
final TitledSeparator separator = new TitledSeparator();
|
||||
separator.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
|
||||
separator.setBackground(backgroundColor);
|
||||
return separator;
|
||||
/*
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
final JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL);
|
||||
panel.setPreferredSize(new Dimension(0, 3));
|
||||
panel.add(separator, BorderLayout.SOUTH);
|
||||
panel.setBackground(backgroundColor);
|
||||
return panel;
|
||||
*/
|
||||
}
|
||||
|
||||
private class CalcElementsThread implements Runnable {
|
||||
|
||||
+15
-12
@@ -96,6 +96,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
boolean previousElemSeparator = false;
|
||||
boolean wasElement = false;
|
||||
|
||||
List<Pair<String, MinusculeMatcher>> patternsAndMatchers = getPatternsAndMatchers(qualifierPattern, base);
|
||||
for (String name : namesList) {
|
||||
indicator.checkCanceled();
|
||||
if (name == ChooseByNameBase.NON_PREFIX_SEPARATOR) {
|
||||
@@ -109,7 +110,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
if (elements.length > 1) {
|
||||
sameNameElements.clear();
|
||||
for (final Object element : elements) {
|
||||
if (matchesQualifier(element, qualifierPattern, base)) {
|
||||
if (matchesQualifier(element, base, patternsAndMatchers)) {
|
||||
sameNameElements.add(element);
|
||||
}
|
||||
}
|
||||
@@ -121,7 +122,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
wasElement = true;
|
||||
}
|
||||
}
|
||||
else if (elements.length == 1 && matchesQualifier(elements[0], qualifierPattern, base)) {
|
||||
else if (elements.length == 1 && matchesQualifier(elements[0], base, patternsAndMatchers)) {
|
||||
if (previousElemSeparator && !consumer.process(ChooseByNameBase.NON_PREFIX_SEPARATOR)) return;
|
||||
if (!consumer.process(elements[0])) return;
|
||||
previousElemSeparator = false;
|
||||
@@ -181,20 +182,12 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
}
|
||||
|
||||
private static boolean matchesQualifier(final Object element,
|
||||
@NotNull final String qualifierPattern,
|
||||
@NotNull final ChooseByNameBase base) {
|
||||
@NotNull final ChooseByNameBase base,
|
||||
final List<Pair<String, MinusculeMatcher>> patternsAndMatchers) {
|
||||
final String name = base.getModel().getFullName(element);
|
||||
if (name == null) return false;
|
||||
|
||||
final List<String> suspects = split(name, base);
|
||||
final List<Pair<String, MinusculeMatcher>> patternsAndMatchers =
|
||||
ContainerUtil.map2List(split(qualifierPattern, base), new Function<String, Pair<String, MinusculeMatcher>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<String, MinusculeMatcher> fun(String s) {
|
||||
return Pair.create(getNamePattern(base, s), buildPatternMatcher(getNamePattern(base, s), NameUtil.MatchingCaseSensitivity.NONE));
|
||||
}
|
||||
});
|
||||
|
||||
int matchPosition = 0;
|
||||
|
||||
@@ -224,6 +217,16 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
return true;
|
||||
}
|
||||
|
||||
private static List<Pair<String, MinusculeMatcher>> getPatternsAndMatchers(String qualifierPattern, final ChooseByNameBase base) {
|
||||
return ContainerUtil.map2List(split(qualifierPattern, base), new Function<String, Pair<String, MinusculeMatcher>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<String, MinusculeMatcher> fun(String s) {
|
||||
return Pair.create(getNamePattern(base, s), buildPatternMatcher(getNamePattern(base, s), NameUtil.MatchingCaseSensitivity.NONE));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> filterNames(@NotNull ChooseByNameBase base, @NotNull String[] names, @NotNull String pattern) {
|
||||
|
||||
+40
-19
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package com.intellij.ide.util.projectWizard;
|
||||
|
||||
import com.intellij.ide.startup.StartupManagerEx;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.platform.WebProjectGenerator;
|
||||
@@ -30,6 +30,7 @@ import com.intellij.ui.ListCellRendererWrapper;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -46,7 +47,6 @@ import java.util.Map;
|
||||
*/
|
||||
public class WebModuleGenerationStep extends ModuleWizardStep {
|
||||
|
||||
private final Project myProject;
|
||||
private final ModuleBuilder myModuleBuilder;
|
||||
private final Icon myIcon;
|
||||
private final String myHelpId;
|
||||
@@ -55,11 +55,9 @@ public class WebModuleGenerationStep extends ModuleWizardStep {
|
||||
private WebProjectGenerator myCurrentGenerator;
|
||||
private JPanel myRightPanel;
|
||||
|
||||
public WebModuleGenerationStep(@Nullable Project project,
|
||||
@NotNull ModuleBuilder moduleBuilder,
|
||||
public WebModuleGenerationStep(@NotNull ModuleBuilder moduleBuilder,
|
||||
@NotNull Icon icon,
|
||||
@NotNull String helpId) {
|
||||
myProject = project;
|
||||
myModuleBuilder = moduleBuilder;
|
||||
myIcon = icon;
|
||||
myHelpId = helpId;
|
||||
@@ -126,11 +124,6 @@ public class WebModuleGenerationStep extends ModuleWizardStep {
|
||||
splitPane.setRightComponent(myRightPanel);
|
||||
|
||||
generatorList.setSelectedValue(emptyProjectGenerator, true);
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
generatorList.requestFocusInWindow();
|
||||
}
|
||||
}, ModalityState.any());
|
||||
return splitPane;
|
||||
}
|
||||
|
||||
@@ -202,7 +195,7 @@ public class WebModuleGenerationStep extends ModuleWizardStep {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void updateDataModel() {
|
||||
WebProjectGenerator generator = myCurrentGenerator;
|
||||
final WebProjectGenerator generator = myCurrentGenerator;
|
||||
if (generator == null) {
|
||||
throw new RuntimeException("Current generator should be not-null");
|
||||
}
|
||||
@@ -210,14 +203,42 @@ public class WebModuleGenerationStep extends ModuleWizardStep {
|
||||
if (peer == null) {
|
||||
throw new RuntimeException("Peer should be not-null for " + myCurrentGenerator.getName());
|
||||
}
|
||||
Object settings = peer.getSettings();
|
||||
final Object settings = peer.getSettings();
|
||||
File dir = new File(myModuleBuilder.getModuleFileDirectory());
|
||||
VirtualFile moduleDir = LocalFileSystem.getInstance().findFileByIoFile(dir);
|
||||
if (moduleDir == null || !moduleDir.isValid()) {
|
||||
moduleDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir);
|
||||
}
|
||||
final VirtualFile moduleDir = VfsUtil.findFileByIoFile(dir, true);
|
||||
if (moduleDir != null && moduleDir.isValid()) {
|
||||
generator.generateProject(myProject, moduleDir, settings, null);
|
||||
myModuleBuilder.addListener(new ModuleBuilderListener() {
|
||||
@Override
|
||||
public void moduleCreated(@NotNull final Module module) {
|
||||
myModuleBuilder.removeListener(this);
|
||||
|
||||
final Project project = module.getProject();
|
||||
final Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
generator.generateProject(project, moduleDir, settings, module);
|
||||
}
|
||||
};
|
||||
final boolean scheduledAsPostStartupActivity;
|
||||
StartupManagerEx startupManager = StartupManagerEx.getInstanceEx(project);
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
synchronized (startupManager) {
|
||||
scheduledAsPostStartupActivity = !startupManager.postStartupActivityPassed();
|
||||
if (scheduledAsPostStartupActivity) {
|
||||
startupManager.registerPostStartupActivity(task);
|
||||
}
|
||||
}
|
||||
if (!scheduledAsPostStartupActivity) {
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
if (!project.isDisposed()) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +259,7 @@ public class WebModuleGenerationStep extends ModuleWizardStep {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateProject(Project project, VirtualFile baseDir, Object settings, Module module) {}
|
||||
public void generateProject(@NotNull Project project, @NotNull VirtualFile baseDir, @NotNull Object settings, @NotNull Module module) {}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -21,7 +21,6 @@ public class WebModuleType extends WebModuleTypeBase<ModuleBuilder> {
|
||||
@Override
|
||||
public ModuleWizardStep[] createWizardSteps(WizardContext wizardContext, ModuleBuilder moduleBuilder, ModulesProvider modulesProvider) {
|
||||
WebModuleGenerationStep generationStep = new WebModuleGenerationStep(
|
||||
wizardContext.getProject(),
|
||||
moduleBuilder,
|
||||
wizardContext.getStepIcon(),
|
||||
"reference.dialogs.new.project.fromScratch.webModuleGeneration"
|
||||
|
||||
+7
-2
@@ -21,6 +21,7 @@ import com.intellij.psi.ElementManipulators;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.impl.source.resolve.ResolveCache;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -46,9 +47,13 @@ public abstract class CachingReference implements PsiReference, EmptyResolveMess
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
public static <T extends PsiElement> ElementManipulator<T> getManipulator(T currentElement){
|
||||
return ElementManipulators.getManipulator(currentElement);
|
||||
ElementManipulator<T> manipulator = ElementManipulators.getManipulator(currentElement);
|
||||
if (manipulator == null) {
|
||||
throw new IncorrectOperationException("Manipulator for this element is not defined: " + currentElement);
|
||||
}
|
||||
return manipulator;
|
||||
}
|
||||
|
||||
private static class MyResolver implements ResolveCache.Resolver {
|
||||
|
||||
+12
-14
@@ -399,18 +399,15 @@ public class FileReference implements FileReferenceOwner, PsiPolyVariantReferenc
|
||||
@Override
|
||||
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
|
||||
final ElementManipulator<PsiElement> manipulator = CachingReference.getManipulator(getElement());
|
||||
if (manipulator != null) {
|
||||
myFileReferenceSet.setElement(manipulator.handleContentChange(getElement(), getRangeInElement(), newElementName));
|
||||
//Correct ranges
|
||||
int delta = newElementName.length() - myRange.getLength();
|
||||
myRange = new TextRange(getRangeInElement().getStartOffset(), getRangeInElement().getStartOffset() + newElementName.length());
|
||||
FileReference[] references = myFileReferenceSet.getAllReferences();
|
||||
for (int idx = myIndex + 1; idx < references.length; idx++) {
|
||||
references[idx].myRange = references[idx].myRange.shiftRight(delta);
|
||||
}
|
||||
return myFileReferenceSet.getElement();
|
||||
myFileReferenceSet.setElement(manipulator.handleContentChange(getElement(), getRangeInElement(), newElementName));
|
||||
//Correct ranges
|
||||
int delta = newElementName.length() - myRange.getLength();
|
||||
myRange = new TextRange(getRangeInElement().getStartOffset(), getRangeInElement().getStartOffset() + newElementName.length());
|
||||
FileReference[] references = myFileReferenceSet.getAllReferences();
|
||||
for (int idx = myIndex + 1; idx < references.length; idx++) {
|
||||
references[idx].myRange = references[idx].myRange.shiftRight(delta);
|
||||
}
|
||||
throw new IncorrectOperationException("Manipulator for this element is not defined: " + getElement());
|
||||
return myFileReferenceSet.getElement();
|
||||
}
|
||||
|
||||
public PsiElement bindToElement(@NotNull final PsiElement element, final boolean absolute) throws IncorrectOperationException {
|
||||
@@ -535,11 +532,12 @@ public class FileReference implements FileReferenceOwner, PsiPolyVariantReferenc
|
||||
|
||||
protected PsiElement rename(final String newName) throws IncorrectOperationException {
|
||||
final TextRange range = new TextRange(myFileReferenceSet.getStartInElement(), getRangeInElement().getEndOffset());
|
||||
final ElementManipulator<PsiElement> manipulator = CachingReference.getManipulator(getElement());
|
||||
PsiElement element = getElement();
|
||||
final ElementManipulator<PsiElement> manipulator = CachingReference.getManipulator(element);
|
||||
if (manipulator == null) {
|
||||
throw new IncorrectOperationException("Manipulator not defined for: " + getElement());
|
||||
throw new IncorrectOperationException("Manipulator not defined for: " + element + " of class " + element.getClass());
|
||||
}
|
||||
return manipulator.handleContentChange(getElement(), range, newName);
|
||||
return manipulator.handleContentChange(element, range, newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -190,7 +190,7 @@ public abstract class InplaceRefactoring {
|
||||
return buildTemplateAndStart(refs, stringUsages, scope, containingFile);
|
||||
}
|
||||
|
||||
protected boolean notSameFile(@Nullable VirtualFile file, PsiFile containingFile) {
|
||||
protected boolean notSameFile(@Nullable VirtualFile file, @NotNull PsiFile containingFile) {
|
||||
return !Comparing.equal(getTopLevelVirtualFile(containingFile.getViewProvider()), file);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -125,9 +125,9 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean notSameFile(@Nullable VirtualFile file, PsiFile containingFile) {
|
||||
protected boolean notSameFile(@Nullable VirtualFile file, @NotNull PsiFile containingFile) {
|
||||
final PsiFile currentFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
|
||||
return currentFile == null || containingFile != currentFile;
|
||||
return currentFile == null || InjectedLanguageUtil.getTopLevelFile(containingFile) != InjectedLanguageUtil.getTopLevelFile(currentFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -80,7 +80,7 @@ public class DetailController implements TreeSelectionListener, ListSelectionLis
|
||||
}, 100);
|
||||
}
|
||||
|
||||
void updateDetailViewLater() {
|
||||
public void selectionChanged() {
|
||||
doUpdateDetailView();
|
||||
}
|
||||
|
||||
@@ -105,11 +105,11 @@ public class DetailController implements TreeSelectionListener, ListSelectionLis
|
||||
|
||||
@Override
|
||||
public void valueChanged(TreeSelectionEvent event) {
|
||||
updateDetailViewLater();
|
||||
selectionChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent event) {
|
||||
updateDetailViewLater();
|
||||
selectionChanged();
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,6 @@ import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
@@ -29,25 +27,27 @@ import java.awt.*;
|
||||
*
|
||||
* @author Vladimir Kondratyev
|
||||
*/
|
||||
public abstract class ColoredListCellRenderer extends SimpleColoredComponent implements ListCellRenderer{
|
||||
public abstract class ColoredListCellRenderer extends SimpleColoredComponent implements ListCellRenderer {
|
||||
protected boolean mySelected;
|
||||
protected Color myForeground;
|
||||
protected Color mySelectionForeground;
|
||||
|
||||
public ColoredListCellRenderer(){
|
||||
public ColoredListCellRenderer() {
|
||||
setFocusBorderAroundIcon(true);
|
||||
getIpad().left = UIUtil.getListCellHPadding();
|
||||
getIpad().right = UIUtil.getListCellHPadding();
|
||||
}
|
||||
|
||||
public Component getListCellRendererComponent(
|
||||
final JList list,
|
||||
final Object value,
|
||||
final int index,
|
||||
final boolean selected,
|
||||
final boolean hasFocus
|
||||
){
|
||||
public Component getListCellRendererComponent(JList list,
|
||||
Object value,
|
||||
int index,
|
||||
boolean selected,
|
||||
boolean hasFocus) {
|
||||
clear();
|
||||
|
||||
mySelected=selected;
|
||||
mySelected = selected;
|
||||
myForeground = list.getForeground();
|
||||
mySelectionForeground = list.getSelectionForeground();
|
||||
if (UIUtil.isWinLafOnVista()) {
|
||||
// the system draws a gradient background on the combobox selected item - don't overdraw it with our solid background
|
||||
if (index == -1) {
|
||||
@@ -60,17 +60,12 @@ public abstract class ColoredListCellRenderer extends SimpleColoredComponent imp
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(selected){
|
||||
setBackground(list.getSelectionBackground());
|
||||
}else{
|
||||
setBackground(null);
|
||||
}
|
||||
setBackground(selected ? list.getSelectionBackground() : null);
|
||||
}
|
||||
|
||||
setPaintFocusBorder(hasFocus);
|
||||
|
||||
customizeCellRenderer(list, value, index, selected, hasFocus);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -78,16 +73,12 @@ public abstract class ColoredListCellRenderer extends SimpleColoredComponent imp
|
||||
* When the item is selected then we use default tree's selection foreground.
|
||||
* It guaranties readability of selected text in any LAF.
|
||||
*/
|
||||
public final void append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes, boolean isMainText) {
|
||||
if(mySelected) {
|
||||
super.append(
|
||||
fragment,
|
||||
new SimpleTextAttributes(
|
||||
attributes.getStyle(), UIUtil.getListSelectionForeground()
|
||||
), isMainText);
|
||||
public final void append(@NotNull String fragment, @NotNull SimpleTextAttributes attributes, boolean isMainText) {
|
||||
if (mySelected) {
|
||||
super.append(fragment, new SimpleTextAttributes(attributes.getStyle(), mySelectionForeground), isMainText);
|
||||
}
|
||||
else if (attributes.getFgColor() == null) {
|
||||
super.append(fragment, new SimpleTextAttributes(attributes.getStyle(), UIUtil.getListForeground()), isMainText);
|
||||
super.append(fragment, new SimpleTextAttributes(attributes.getStyle(), myForeground), isMainText);
|
||||
}
|
||||
else {
|
||||
super.append(fragment, attributes, isMainText);
|
||||
@@ -98,23 +89,17 @@ public abstract class ColoredListCellRenderer extends SimpleColoredComponent imp
|
||||
// There is a bug in BasicComboPopup. It does not add renderer into CellRendererPane,
|
||||
// so font can be null here.
|
||||
|
||||
final Font oldFont = getFont();
|
||||
if(oldFont == null){
|
||||
Font oldFont = getFont();
|
||||
if (oldFont == null) {
|
||||
setFont(UIUtil.getListFont());
|
||||
}
|
||||
final Dimension result = super.getPreferredSize();
|
||||
if(oldFont == null){
|
||||
Dimension result = super.getPreferredSize();
|
||||
if (oldFont == null) {
|
||||
setFont(null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract void customizeCellRenderer(
|
||||
JList list,
|
||||
Object value,
|
||||
int index,
|
||||
boolean selected,
|
||||
boolean hasFocus
|
||||
);
|
||||
protected abstract void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus);
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ public class LinkLabel extends JLabel {
|
||||
}
|
||||
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
final Border border = getBorder();
|
||||
int shiftX = 0;
|
||||
int shiftY = 0;
|
||||
|
||||
+92
-27
@@ -17,18 +17,26 @@ package com.intellij.openapi.editor.actions;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.ui.SplitterProportionsDataImpl;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.colors.EditorFontType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.openapi.ui.SplitterProportionsData;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
@@ -38,18 +46,21 @@ import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
private JList myList;
|
||||
private List<Data> myAllContents;
|
||||
|
||||
private Editor myViewer;
|
||||
|
||||
private final boolean myUseIdeaEditor;
|
||||
|
||||
private Splitter mySplitter;
|
||||
private final JList myList;
|
||||
private final Splitter mySplitter;
|
||||
private final Project myProject;
|
||||
private final boolean myAllowMultipleSelections;
|
||||
private final Alarm myUpdateAlarm;
|
||||
private Icon myListEntryIcon = AllIcons.FileTypes.Text;
|
||||
|
||||
public ContentChooser(Project project, String title, boolean useIdeaEditor) {
|
||||
this(project, title, useIdeaEditor, false);
|
||||
@@ -60,6 +71,9 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
myProject = project;
|
||||
myUseIdeaEditor = useIdeaEditor;
|
||||
myAllowMultipleSelections = allowMultipleSelections;
|
||||
myUpdateAlarm = new Alarm(getDisposable());
|
||||
mySplitter = new Splitter(true, 0.3f);
|
||||
myList = new JBList();
|
||||
|
||||
setOKButtonText(CommonBundle.getOkButtonText());
|
||||
setTitle(title);
|
||||
@@ -67,6 +81,14 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
init();
|
||||
}
|
||||
|
||||
public void setContentIcon(@Nullable Icon icon) {
|
||||
myListEntryIcon = icon;
|
||||
}
|
||||
|
||||
public void setSplitterOrientation(boolean vertical) {
|
||||
mySplitter.setOrientation(vertical);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myList;
|
||||
@@ -74,10 +96,17 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
myList = new JBList();
|
||||
final int selectionMode = myAllowMultipleSelections ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
|
||||
final int selectionMode = myAllowMultipleSelections ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
|
||||
: ListSelectionModel.SINGLE_SELECTION;
|
||||
myList.setSelectionMode(selectionMode);
|
||||
if (myUseIdeaEditor) {
|
||||
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
|
||||
myList.setFont(scheme.getFont(EditorFontType.PLAIN));
|
||||
Color fg = ObjectUtils.chooseNotNull(scheme.getDefaultForeground(), UIUtil.getListForeground());
|
||||
Color bg = ObjectUtils.chooseNotNull(scheme.getDefaultBackground(), UIUtil.getListBackground());
|
||||
myList.setForeground(fg);
|
||||
myList.setBackground(bg);
|
||||
}
|
||||
|
||||
rebuildListContent();
|
||||
|
||||
@@ -91,11 +120,6 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
|
||||
|
||||
myList.setCellRenderer(new MyListCellRenderer());
|
||||
|
||||
if (myAllContents.size() > 0) {
|
||||
myList.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
myList.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
@@ -131,19 +155,31 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
}
|
||||
});
|
||||
|
||||
mySplitter = new Splitter(true);
|
||||
mySplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myList));
|
||||
mySplitter.setSecondComponent(new JPanel());
|
||||
updateViewerForSelection();
|
||||
|
||||
ListScrollingUtil.installActions(myList);
|
||||
ListScrollingUtil.ensureSelectionExists(myList);
|
||||
updateViewerForSelection();
|
||||
myList.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
updateViewerForSelection();
|
||||
myUpdateAlarm.cancelAllRequests();
|
||||
myUpdateAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateViewerForSelection();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
|
||||
mySplitter.setPreferredSize(new Dimension(500, 500));
|
||||
|
||||
SplitterProportionsData d = new SplitterProportionsDataImpl();
|
||||
d.externalizeToDimensionService(getClass().getName());
|
||||
d.restoreSplitterProportions(mySplitter);
|
||||
|
||||
new ListSpeedSearch(myList);
|
||||
|
||||
return mySplitter;
|
||||
@@ -153,7 +189,7 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
|
||||
@Override
|
||||
protected String getDimensionServiceKey() {
|
||||
return "#com.intellij.openapi.editor.actions.MultiplePasteAction.Chooser";
|
||||
return getClass().getName(); // store different values for multi-paste, history and commit messages
|
||||
}
|
||||
|
||||
private void updateViewerForSelection() {
|
||||
@@ -169,14 +205,10 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
}
|
||||
|
||||
if (myUseIdeaEditor) {
|
||||
Document doc = EditorFactory.getInstance().createDocument(fullString);
|
||||
myViewer = EditorFactory.getInstance().createViewer(doc, myProject);
|
||||
myViewer.getComponent().setPreferredSize(new Dimension(300, 500));
|
||||
myViewer.getSettings().setFoldingOutlineShown(false);
|
||||
myViewer.getSettings().setLineNumbersShown(false);
|
||||
myViewer.getSettings().setLineMarkerAreaShown(false);
|
||||
myViewer.getSettings().setIndentGuidesShown(false);
|
||||
mySplitter.setSecondComponent(myViewer.getComponent());
|
||||
myViewer = createIdeaEditor(fullString);
|
||||
JComponent component = myViewer.getComponent();
|
||||
component.setPreferredSize(new Dimension(300, 500));
|
||||
mySplitter.setSecondComponent(component);
|
||||
} else {
|
||||
final JTextArea textArea = new JTextArea(fullString);
|
||||
textArea.setRows(3);
|
||||
@@ -190,9 +222,24 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
mySplitter.revalidate();
|
||||
}
|
||||
|
||||
protected Editor createIdeaEditor(String text) {
|
||||
Document doc = EditorFactory.getInstance().createDocument(text);
|
||||
Editor editor = EditorFactory.getInstance().createViewer(doc, myProject);
|
||||
editor.getSettings().setFoldingOutlineShown(false);
|
||||
editor.getSettings().setLineNumbersShown(false);
|
||||
editor.getSettings().setLineMarkerAreaShown(false);
|
||||
editor.getSettings().setIndentGuidesShown(false);
|
||||
return editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
SplitterProportionsData d = new SplitterProportionsDataImpl();
|
||||
d.externalizeToDimensionService(getClass().getName());
|
||||
d.saveSplitterProportions(mySplitter);
|
||||
|
||||
if (myViewer != null) {
|
||||
EditorFactory.getInstance().releaseEditor(myViewer);
|
||||
myViewer = null;
|
||||
@@ -241,6 +288,12 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
return myList.getSelectedIndex();
|
||||
}
|
||||
|
||||
public void setSelectedIndex(int index) {
|
||||
myList.setSelectedIndex(index);
|
||||
ListScrollingUtil.ensureIndexIsVisible(myList, index, 0);
|
||||
updateViewerForSelection();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public int[] getSelectedIndices() {
|
||||
return myList.getSelectedIndices();
|
||||
@@ -260,7 +313,7 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class MyListCellRenderer extends ColoredListCellRenderer {
|
||||
private class MyListCellRenderer extends ColoredListCellRenderer {
|
||||
@Override
|
||||
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
|
||||
// Fix GTK background
|
||||
@@ -268,11 +321,23 @@ public abstract class ContentChooser<Data> extends DialogWrapper {
|
||||
final Color background = selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground();
|
||||
UIUtil.changeBackGround(this, background);
|
||||
}
|
||||
setIcon(AllIcons.FileTypes.Text);
|
||||
if (index <= 9) {
|
||||
append(String.valueOf((index + 1) % 10) + " ", SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
setIcon(myListEntryIcon);
|
||||
if (myUseIdeaEditor) {
|
||||
int max = list.getModel().getSize();
|
||||
String indexString = String.valueOf(index + 1);
|
||||
int count = String.valueOf(max).length() - indexString.length();
|
||||
char[] spaces = new char[count];
|
||||
Arrays.fill(spaces, ' ');
|
||||
String prefix = indexString + new String(spaces) + " ";
|
||||
append(prefix, SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
}
|
||||
append((String) value, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
String text = (String)value;
|
||||
|
||||
FontMetrics metrics = list.getFontMetrics(list.getFont());
|
||||
int charWidth = metrics.charWidth('m');
|
||||
int maxLength = list.getParent().getParent().getWidth() * 3 / charWidth / 2;
|
||||
text = StringUtil.first(text, maxLength, true); // do not paint long strings
|
||||
append(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public abstract class WebProjectGenerator<T> implements DirectoryProjectGenerato
|
||||
public abstract String getName();
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@NotNull
|
||||
public final T showGenerationSettings(VirtualFile baseDir) throws ProcessCanceledException {
|
||||
GeneratorPeer<T> peer = createPeer();
|
||||
DialogWrapper dialog = new MyDialogWrapper(peer);
|
||||
@@ -53,7 +53,7 @@ public abstract class WebProjectGenerator<T> implements DirectoryProjectGenerato
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void generateProject(Project project, VirtualFile baseDir, T settings, Module module);
|
||||
public abstract void generateProject(@NotNull Project project, @NotNull VirtualFile baseDir, @NotNull T settings, @NotNull Module module);
|
||||
|
||||
/**
|
||||
* Always returns {@link ValidationResult#OK}.
|
||||
|
||||
@@ -197,7 +197,6 @@
|
||||
<mouse-shortcut keystroke="button2" />
|
||||
<keyboard-shortcut first-keystroke="control B" />
|
||||
</action>
|
||||
<action id="GotoFile" />
|
||||
<action id="GotoImplementation">
|
||||
<mouse-shortcut keystroke="meta alt button1" />
|
||||
<keyboard-shortcut first-keystroke="control alt B" />
|
||||
@@ -211,6 +210,12 @@
|
||||
<action id="GotoPreviousError">
|
||||
<keyboard-shortcut first-keystroke="shift meta QUOTE" />
|
||||
</action>
|
||||
<action id="GotoClass">
|
||||
<keyboard-shortcut first-keystroke="meta O" />
|
||||
</action>
|
||||
<action id="GotoFile">
|
||||
<keyboard-shortcut first-keystroke="meta alt O" />
|
||||
</action>
|
||||
<action id="GotoSymbol">
|
||||
<keyboard-shortcut first-keystroke="shift meta O" />
|
||||
<keyboard-shortcut first-keystroke="shift meta alt N" />
|
||||
@@ -319,7 +324,6 @@
|
||||
<action id="FileChooser.NewFolder">
|
||||
<keyboard-shortcut first-keystroke="alt INSERT" />
|
||||
</action>
|
||||
<action id="GotoClass" />
|
||||
<action id="NewElement">
|
||||
<keyboard-shortcut first-keystroke="control ENTER" />
|
||||
<keyboard-shortcut first-keystroke="meta N" />
|
||||
|
||||
@@ -399,6 +399,10 @@ public class NameUtilTest extends UsefulTestCase {
|
||||
assertFalse(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic"));
|
||||
assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
|
||||
assertFalse(new MinusculeMatcher("Str", NameUtil.MatchingCaseSensitivity.ALL).matches("SomeThingRidiculous"));
|
||||
assertFalse(new MinusculeMatcher("*list*", NameUtil.MatchingCaseSensitivity.ALL).matches("List"));
|
||||
assertFalse(new MinusculeMatcher("*list*", NameUtil.MatchingCaseSensitivity.ALL).matches("AbstractList"));
|
||||
assertFalse(new MinusculeMatcher("java.util.list", NameUtil.MatchingCaseSensitivity.ALL).matches("java.util.List"));
|
||||
assertFalse(new MinusculeMatcher("java.util.list", NameUtil.MatchingCaseSensitivity.ALL).matches("java.util.AbstractList"));
|
||||
}
|
||||
|
||||
public void testMatchingFragments() {
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.openapi.util.text;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.util.*;
|
||||
@@ -2351,4 +2352,43 @@ public class StringUtil extends StringUtilRt {
|
||||
public static String getShortName(@NotNull String fqName, char separator) {
|
||||
return StringUtilRt.getShortName(fqName, separator);
|
||||
}
|
||||
|
||||
public static class BombedCharSequence implements CharSequence {
|
||||
private CharSequence delegate;
|
||||
private long myTime;
|
||||
private long i = 0;
|
||||
|
||||
public BombedCharSequence(CharSequence sequence, long time) {
|
||||
delegate = sequence;
|
||||
myTime = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
check();
|
||||
return delegate.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int i) {
|
||||
check();
|
||||
return delegate.charAt(i);
|
||||
}
|
||||
|
||||
private void check() {
|
||||
++i;
|
||||
if (i % 1000 == 0) {
|
||||
long l = System.currentTimeMillis();
|
||||
if (l >= myTime) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int i, int i1) {
|
||||
check();
|
||||
return delegate.subSequence(i, i1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
package com.intellij.util.io.tar;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The TarBuffer class implements the tar archive concept
|
||||
* of a buffered input stream. This concept goes back to the
|
||||
* days of blocked tape drives and special io devices. In the
|
||||
* Java universe, the only real function that this class
|
||||
* performs is to ensure that files have the correct "block"
|
||||
* size, or other tars will complain.
|
||||
* <p>
|
||||
* You should never have a need to access this class directly.
|
||||
* TarBuffers are created by Tar IO Streams.
|
||||
*
|
||||
*/
|
||||
|
||||
// Copy-pasted from org.apache.tools.tar.TarBuffer
|
||||
public class TarBuffer {
|
||||
|
||||
/** Default record size */
|
||||
public static final int DEFAULT_RCDSIZE = (512);
|
||||
|
||||
/** Default block size */
|
||||
public static final int DEFAULT_BLKSIZE = (DEFAULT_RCDSIZE * 20);
|
||||
|
||||
private InputStream inStream;
|
||||
private OutputStream outStream;
|
||||
private byte[] blockBuffer;
|
||||
private int currBlkIdx;
|
||||
private int currRecIdx;
|
||||
private int blockSize;
|
||||
private int recordSize;
|
||||
private int recsPerBlock;
|
||||
private boolean debug;
|
||||
|
||||
/**
|
||||
* Constructor for a TarBuffer on an input stream.
|
||||
* @param inStream the input stream to use
|
||||
*/
|
||||
public TarBuffer(InputStream inStream) {
|
||||
this(inStream, TarBuffer.DEFAULT_BLKSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a TarBuffer on an input stream.
|
||||
* @param inStream the input stream to use
|
||||
* @param blockSize the block size to use
|
||||
*/
|
||||
public TarBuffer(InputStream inStream, int blockSize) {
|
||||
this(inStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a TarBuffer on an input stream.
|
||||
* @param inStream the input stream to use
|
||||
* @param blockSize the block size to use
|
||||
* @param recordSize the record size to use
|
||||
*/
|
||||
public TarBuffer(InputStream inStream, int blockSize, int recordSize) {
|
||||
this.inStream = inStream;
|
||||
this.outStream = null;
|
||||
|
||||
this.initialize(blockSize, recordSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a TarBuffer on an output stream.
|
||||
* @param outStream the output stream to use
|
||||
*/
|
||||
public TarBuffer(OutputStream outStream) {
|
||||
this(outStream, TarBuffer.DEFAULT_BLKSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a TarBuffer on an output stream.
|
||||
* @param outStream the output stream to use
|
||||
* @param blockSize the block size to use
|
||||
*/
|
||||
public TarBuffer(OutputStream outStream, int blockSize) {
|
||||
this(outStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a TarBuffer on an output stream.
|
||||
* @param outStream the output stream to use
|
||||
* @param blockSize the block size to use
|
||||
* @param recordSize the record size to use
|
||||
*/
|
||||
public TarBuffer(OutputStream outStream, int blockSize, int recordSize) {
|
||||
this.inStream = null;
|
||||
this.outStream = outStream;
|
||||
|
||||
this.initialize(blockSize, recordSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization common to all constructors.
|
||||
*/
|
||||
private void initialize(int blockSize, int recordSize) {
|
||||
this.debug = false;
|
||||
this.blockSize = blockSize;
|
||||
this.recordSize = recordSize;
|
||||
this.recsPerBlock = (this.blockSize / this.recordSize);
|
||||
this.blockBuffer = new byte[this.blockSize];
|
||||
|
||||
if (this.inStream != null) {
|
||||
this.currBlkIdx = -1;
|
||||
this.currRecIdx = this.recsPerBlock;
|
||||
} else {
|
||||
this.currBlkIdx = 0;
|
||||
this.currRecIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TAR Buffer's block size. Blocks consist of multiple records.
|
||||
* @return the block size
|
||||
*/
|
||||
public int getBlockSize() {
|
||||
return this.blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TAR Buffer's record size.
|
||||
* @return the record size
|
||||
*/
|
||||
public int getRecordSize() {
|
||||
return this.recordSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the debugging flag for the buffer.
|
||||
*
|
||||
* @param debug If true, print debugging output.
|
||||
*/
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an archive record indicate End of Archive. End of
|
||||
* archive is indicated by a record that consists entirely of null bytes.
|
||||
*
|
||||
* @param record The record data to check.
|
||||
* @return true if the record data is an End of Archive
|
||||
*/
|
||||
public boolean isEOFRecord(byte[] record) {
|
||||
for (int i = 0, sz = getRecordSize(); i < sz; ++i) {
|
||||
if (record[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip over a record on the input stream.
|
||||
* @throws java.io.IOException on error
|
||||
*/
|
||||
public void skipRecord() throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("SkipRecord: recIdx = " + currRecIdx
|
||||
+ " blkIdx = " + currBlkIdx);
|
||||
}
|
||||
|
||||
if (inStream == null) {
|
||||
throw new IOException("reading (via skip) from an output buffer");
|
||||
}
|
||||
|
||||
if (currRecIdx >= recsPerBlock) {
|
||||
if (!readBlock()) {
|
||||
return; // UNDONE
|
||||
}
|
||||
}
|
||||
|
||||
currRecIdx++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a record from the input stream and return the data.
|
||||
*
|
||||
* @return The record data.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public byte[] readRecord() throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("ReadRecord: recIdx = " + currRecIdx
|
||||
+ " blkIdx = " + currBlkIdx);
|
||||
}
|
||||
|
||||
if (inStream == null) {
|
||||
throw new IOException("reading from an output buffer");
|
||||
}
|
||||
|
||||
if (currRecIdx >= recsPerBlock) {
|
||||
if (!readBlock()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] result = new byte[recordSize];
|
||||
|
||||
System.arraycopy(blockBuffer,
|
||||
(currRecIdx * recordSize), result, 0,
|
||||
recordSize);
|
||||
|
||||
currRecIdx++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if End-Of-File, else true
|
||||
*/
|
||||
private boolean readBlock() throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("ReadBlock: blkIdx = " + currBlkIdx);
|
||||
}
|
||||
|
||||
if (inStream == null) {
|
||||
throw new IOException("reading from an output buffer");
|
||||
}
|
||||
|
||||
currRecIdx = 0;
|
||||
|
||||
int offset = 0;
|
||||
int bytesNeeded = blockSize;
|
||||
|
||||
while (bytesNeeded > 0) {
|
||||
long numBytes = inStream.read(blockBuffer, offset,
|
||||
bytesNeeded);
|
||||
|
||||
//
|
||||
// NOTE
|
||||
// We have fit EOF, and the block is not full!
|
||||
//
|
||||
// This is a broken archive. It does not follow the standard
|
||||
// blocking algorithm. However, because we are generous, and
|
||||
// it requires little effort, we will simply ignore the error
|
||||
// and continue as if the entire block were read. This does
|
||||
// not appear to break anything upstream. We used to return
|
||||
// false in this case.
|
||||
//
|
||||
// Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
|
||||
//
|
||||
if (numBytes == -1) {
|
||||
if (offset == 0) {
|
||||
// Ensure that we do not read gigabytes of zeros
|
||||
// for a corrupt tar file.
|
||||
// See http://issues.apache.org/bugzilla/show_bug.cgi?id=39924
|
||||
return false;
|
||||
}
|
||||
// However, just leaving the unread portion of the buffer dirty does
|
||||
// cause problems in some cases. This problem is described in
|
||||
// http://issues.apache.org/bugzilla/show_bug.cgi?id=29877
|
||||
//
|
||||
// The solution is to fill the unused portion of the buffer with zeros.
|
||||
|
||||
Arrays.fill(blockBuffer, offset, offset + bytesNeeded, (byte)0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
offset += numBytes;
|
||||
bytesNeeded -= numBytes;
|
||||
|
||||
if (numBytes != blockSize) {
|
||||
if (debug) {
|
||||
System.err.println("ReadBlock: INCOMPLETE READ "
|
||||
+ numBytes + " of " + blockSize
|
||||
+ " bytes read.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currBlkIdx++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current block number, zero based.
|
||||
*
|
||||
* @return The current zero based block number.
|
||||
*/
|
||||
public int getCurrentBlockNum() {
|
||||
return currBlkIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current record number, within the current block, zero based.
|
||||
* Thus, current offset = (currentBlockNum * recsPerBlk) + currentRecNum.
|
||||
*
|
||||
* @return The current zero based record number.
|
||||
*/
|
||||
public int getCurrentRecordNum() {
|
||||
return currRecIdx - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an archive record to the archive.
|
||||
*
|
||||
* @param record The record data to write to the archive.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public void writeRecord(byte[] record) throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("WriteRecord: recIdx = " + currRecIdx
|
||||
+ " blkIdx = " + currBlkIdx);
|
||||
}
|
||||
|
||||
if (outStream == null) {
|
||||
throw new IOException("writing to an input buffer");
|
||||
}
|
||||
|
||||
if (record.length != recordSize) {
|
||||
throw new IOException("record to write has length '"
|
||||
+ record.length
|
||||
+ "' which is not the record size of '"
|
||||
+ recordSize + "'");
|
||||
}
|
||||
|
||||
if (currRecIdx >= recsPerBlock) {
|
||||
writeBlock();
|
||||
}
|
||||
|
||||
System.arraycopy(record, 0, blockBuffer,
|
||||
(currRecIdx * recordSize),
|
||||
recordSize);
|
||||
|
||||
currRecIdx++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an archive record to the archive, where the record may be
|
||||
* inside of a larger array buffer. The buffer must be "offset plus
|
||||
* record size" long.
|
||||
*
|
||||
* @param buf The buffer containing the record data to write.
|
||||
* @param offset The offset of the record data within buf.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public void writeRecord(byte[] buf, int offset) throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("WriteRecord: recIdx = " + currRecIdx
|
||||
+ " blkIdx = " + currBlkIdx);
|
||||
}
|
||||
|
||||
if (outStream == null) {
|
||||
throw new IOException("writing to an input buffer");
|
||||
}
|
||||
|
||||
if ((offset + recordSize) > buf.length) {
|
||||
throw new IOException("record has length '" + buf.length
|
||||
+ "' with offset '" + offset
|
||||
+ "' which is less than the record size of '"
|
||||
+ recordSize + "'");
|
||||
}
|
||||
|
||||
if (currRecIdx >= recsPerBlock) {
|
||||
writeBlock();
|
||||
}
|
||||
|
||||
System.arraycopy(buf, offset, blockBuffer,
|
||||
(currRecIdx * recordSize),
|
||||
recordSize);
|
||||
|
||||
currRecIdx++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a TarBuffer block to the archive.
|
||||
*/
|
||||
private void writeBlock() throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("WriteBlock: blkIdx = " + currBlkIdx);
|
||||
}
|
||||
|
||||
if (outStream == null) {
|
||||
throw new IOException("writing to an input buffer");
|
||||
}
|
||||
|
||||
outStream.write(blockBuffer, 0, blockSize);
|
||||
outStream.flush();
|
||||
|
||||
currRecIdx = 0;
|
||||
currBlkIdx++;
|
||||
Arrays.fill(blockBuffer, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the current data block if it has any data in it.
|
||||
*/
|
||||
void flushBlock() throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("TarBuffer.flushBlock() called.");
|
||||
}
|
||||
|
||||
if (outStream == null) {
|
||||
throw new IOException("writing to an input buffer");
|
||||
}
|
||||
|
||||
if (currRecIdx > 0) {
|
||||
writeBlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the TarBuffer. If this is an output buffer, also flush the
|
||||
* current block before closing.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (debug) {
|
||||
System.err.println("TarBuffer.closeBuffer().");
|
||||
}
|
||||
|
||||
if (outStream != null) {
|
||||
flushBlock();
|
||||
|
||||
if (outStream != System.out
|
||||
&& outStream != System.err) {
|
||||
outStream.close();
|
||||
|
||||
outStream = null;
|
||||
}
|
||||
} else if (inStream != null) {
|
||||
if (inStream != System.in) {
|
||||
inStream.close();
|
||||
|
||||
inStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.intellij.util.io.tar;
|
||||
|
||||
/**
|
||||
* This interface contains all the definitions used in the package.
|
||||
*
|
||||
*/
|
||||
// CheckStyle:InterfaceIsTypeCheck OFF (bc)
|
||||
// Copy-pasted from org.apache.tools.tar.TarConstants
|
||||
public interface TarConstants {
|
||||
|
||||
/**
|
||||
* The length of the name field in a header buffer.
|
||||
*/
|
||||
int NAMELEN = 100;
|
||||
|
||||
/**
|
||||
* The length of the mode field in a header buffer.
|
||||
*/
|
||||
int MODELEN = 8;
|
||||
|
||||
/**
|
||||
* The length of the user id field in a header buffer.
|
||||
*/
|
||||
int UIDLEN = 8;
|
||||
|
||||
/**
|
||||
* The length of the group id field in a header buffer.
|
||||
*/
|
||||
int GIDLEN = 8;
|
||||
|
||||
/**
|
||||
* The length of the checksum field in a header buffer.
|
||||
*/
|
||||
int CHKSUMLEN = 8;
|
||||
|
||||
/**
|
||||
* The length of the size field in a header buffer.
|
||||
*/
|
||||
int SIZELEN = 12;
|
||||
|
||||
/**
|
||||
* The maximum size of a file in a tar archive (That's 11 sevens, octal).
|
||||
*/
|
||||
long MAXSIZE = 077777777777L;
|
||||
|
||||
/**
|
||||
* The length of the magic field in a header buffer.
|
||||
*/
|
||||
int MAGICLEN = 8;
|
||||
|
||||
/**
|
||||
* The length of the modification time field in a header buffer.
|
||||
*/
|
||||
int MODTIMELEN = 12;
|
||||
|
||||
/**
|
||||
* The length of the user name field in a header buffer.
|
||||
*/
|
||||
int UNAMELEN = 32;
|
||||
|
||||
/**
|
||||
* The length of the group name field in a header buffer.
|
||||
*/
|
||||
int GNAMELEN = 32;
|
||||
|
||||
/**
|
||||
* The length of the devices field in a header buffer.
|
||||
*/
|
||||
int DEVLEN = 8;
|
||||
|
||||
/**
|
||||
* LF_ constants represent the "link flag" of an entry, or more commonly,
|
||||
* the "entry type". This is the "old way" of indicating a normal file.
|
||||
*/
|
||||
byte LF_OLDNORM = 0;
|
||||
|
||||
/**
|
||||
* Normal file type.
|
||||
*/
|
||||
byte LF_NORMAL = (byte) '0';
|
||||
|
||||
/**
|
||||
* Link file type.
|
||||
*/
|
||||
byte LF_LINK = (byte) '1';
|
||||
|
||||
/**
|
||||
* Symbolic link file type.
|
||||
*/
|
||||
byte LF_SYMLINK = (byte) '2';
|
||||
|
||||
/**
|
||||
* Character device file type.
|
||||
*/
|
||||
byte LF_CHR = (byte) '3';
|
||||
|
||||
/**
|
||||
* Block device file type.
|
||||
*/
|
||||
byte LF_BLK = (byte) '4';
|
||||
|
||||
/**
|
||||
* Directory file type.
|
||||
*/
|
||||
byte LF_DIR = (byte) '5';
|
||||
|
||||
/**
|
||||
* FIFO (pipe) file type.
|
||||
*/
|
||||
byte LF_FIFO = (byte) '6';
|
||||
|
||||
/**
|
||||
* Contiguous file type.
|
||||
*/
|
||||
byte LF_CONTIG = (byte) '7';
|
||||
|
||||
/**
|
||||
* The magic tag representing a POSIX tar archive.
|
||||
*/
|
||||
String TMAGIC = "ustar";
|
||||
|
||||
/**
|
||||
* The magic tag representing a GNU tar archive.
|
||||
*/
|
||||
String GNU_TMAGIC = "ustar ";
|
||||
|
||||
/**
|
||||
* The namr of the GNU tar entry which contains a long name.
|
||||
*/
|
||||
String GNU_LONGLINK = "././@LongLink";
|
||||
|
||||
/**
|
||||
* Identifies the *next* file on the tape as having a long name.
|
||||
*/
|
||||
byte LF_GNUTYPE_LONGNAME = (byte) 'L';
|
||||
}
|
||||
@@ -0,0 +1,642 @@
|
||||
package com.intellij.util.io.tar;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* This class represents an entry in a Tar archive. It consists
|
||||
* of the entry's header, as well as the entry's File. Entries
|
||||
* can be instantiated in one of three ways, depending on how
|
||||
* they are to be used.
|
||||
* <p>
|
||||
* TarEntries that are created from the header bytes read from
|
||||
* an archive are instantiated with the TarEntry( byte[] )
|
||||
* constructor. These entries will be used when extracting from
|
||||
* or listing the contents of an archive. These entries have their
|
||||
* header filled in using the header bytes. They also set the File
|
||||
* to null, since they reference an archive entry not a file.
|
||||
* <p>
|
||||
* TarEntries that are created from Files that are to be written
|
||||
* into an archive are instantiated with the TarEntry( File )
|
||||
* constructor. These entries have their header filled in using
|
||||
* the File's information. They also keep a reference to the File
|
||||
* for convenience when writing entries.
|
||||
* <p>
|
||||
* Finally, TarEntries can be constructed from nothing but a name.
|
||||
* This allows the programmer to construct the entry by hand, for
|
||||
* instance when only an InputStream is available for writing to
|
||||
* the archive, and the header information is constructed from
|
||||
* other information. In this case the header fields are set to
|
||||
* defaults and the File is set to null.
|
||||
*
|
||||
* <p>
|
||||
* The C structure for a Tar Entry's header is:
|
||||
* <pre>
|
||||
* struct header {
|
||||
* char name[NAMSIZ];
|
||||
* char mode[8];
|
||||
* char uid[8];
|
||||
* char gid[8];
|
||||
* char size[12];
|
||||
* char mtime[12];
|
||||
* char chksum[8];
|
||||
* char linkflag;
|
||||
* char linkname[NAMSIZ];
|
||||
* char magic[8];
|
||||
* char uname[TUNMLEN];
|
||||
* char gname[TGNMLEN];
|
||||
* char devmajor[8];
|
||||
* char devminor[8];
|
||||
* } header;
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
// Copy-pasted from org.apache.tools.tar.TarEntry
|
||||
|
||||
public class TarEntry implements TarConstants {
|
||||
/** The entry's name. */
|
||||
private StringBuffer name;
|
||||
|
||||
/** The entry's permission mode. */
|
||||
private int mode;
|
||||
|
||||
/** The entry's user id. */
|
||||
private int userId;
|
||||
|
||||
/** The entry's group id. */
|
||||
private int groupId;
|
||||
|
||||
/** The entry's size. */
|
||||
private long size;
|
||||
|
||||
/** The entry's modification time. */
|
||||
private long modTime;
|
||||
|
||||
/** The entry's link flag. */
|
||||
private byte linkFlag;
|
||||
|
||||
/** The entry's link name. */
|
||||
private StringBuffer linkName;
|
||||
|
||||
/** The entry's magic tag. */
|
||||
private StringBuffer magic;
|
||||
|
||||
/** The entry's user name. */
|
||||
private StringBuffer userName;
|
||||
|
||||
/** The entry's group name. */
|
||||
private StringBuffer groupName;
|
||||
|
||||
/** The entry's major device number. */
|
||||
private int devMajor;
|
||||
|
||||
/** The entry's minor device number. */
|
||||
private int devMinor;
|
||||
|
||||
/** The entry's file reference */
|
||||
private File file;
|
||||
|
||||
/** Maximum length of a user's name in the tar file */
|
||||
public static final int MAX_NAMELEN = 31;
|
||||
|
||||
/** Default permissions bits for directories */
|
||||
public static final int DEFAULT_DIR_MODE = 040755;
|
||||
|
||||
/** Default permissions bits for files */
|
||||
public static final int DEFAULT_FILE_MODE = 0100644;
|
||||
|
||||
/** Convert millis to seconds */
|
||||
public static final int MILLIS_PER_SECOND = 1000;
|
||||
|
||||
/**
|
||||
* Construct an empty entry and prepares the header values.
|
||||
*/
|
||||
private TarEntry () {
|
||||
this.magic = new StringBuffer(TMAGIC);
|
||||
this.name = new StringBuffer();
|
||||
this.linkName = new StringBuffer();
|
||||
|
||||
String user = System.getProperty("user.name", "");
|
||||
|
||||
if (user.length() > MAX_NAMELEN) {
|
||||
user = user.substring(0, MAX_NAMELEN);
|
||||
}
|
||||
|
||||
this.userId = 0;
|
||||
this.groupId = 0;
|
||||
this.userName = new StringBuffer(user);
|
||||
this.groupName = new StringBuffer("");
|
||||
this.file = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an entry with only a name. This allows the programmer
|
||||
* to construct the entry's header "by hand". File is set to null.
|
||||
*
|
||||
* @param name the entry name
|
||||
*/
|
||||
public TarEntry(String name) {
|
||||
this(name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an entry with only a name. This allows the programmer
|
||||
* to construct the entry's header "by hand". File is set to null.
|
||||
*
|
||||
* @param name the entry name
|
||||
* @param preserveLeadingSlashes whether to allow leading slashes
|
||||
* in the name.
|
||||
*/
|
||||
public TarEntry(String name, boolean preserveLeadingSlashes) {
|
||||
this();
|
||||
|
||||
name = normalizeFileName(name, preserveLeadingSlashes);
|
||||
boolean isDir = name.endsWith("/");
|
||||
|
||||
this.devMajor = 0;
|
||||
this.devMinor = 0;
|
||||
this.name = new StringBuffer(name);
|
||||
this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;
|
||||
this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
|
||||
this.userId = 0;
|
||||
this.groupId = 0;
|
||||
this.size = 0;
|
||||
this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND;
|
||||
this.linkName = new StringBuffer("");
|
||||
this.userName = new StringBuffer("");
|
||||
this.groupName = new StringBuffer("");
|
||||
this.devMajor = 0;
|
||||
this.devMinor = 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an entry with a name and a link flag.
|
||||
*
|
||||
* @param name the entry name
|
||||
* @param linkFlag the entry link flag.
|
||||
*/
|
||||
public TarEntry(String name, byte linkFlag) {
|
||||
this(name);
|
||||
this.linkFlag = linkFlag;
|
||||
if (linkFlag == LF_GNUTYPE_LONGNAME) {
|
||||
magic = new StringBuffer(GNU_TMAGIC);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an entry for a file. File is set to file, and the
|
||||
* header is constructed from information from the file.
|
||||
*
|
||||
* @param file The file that the entry represents.
|
||||
*/
|
||||
public TarEntry(File file) {
|
||||
this();
|
||||
|
||||
this.file = file;
|
||||
|
||||
String fileName = normalizeFileName(file.getPath(), false);
|
||||
this.linkName = new StringBuffer("");
|
||||
this.name = new StringBuffer(fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
this.mode = DEFAULT_DIR_MODE;
|
||||
this.linkFlag = LF_DIR;
|
||||
|
||||
int nameLength = name.length();
|
||||
if (nameLength == 0 || name.charAt(nameLength - 1) != '/') {
|
||||
this.name.append("/");
|
||||
}
|
||||
this.size = 0;
|
||||
} else {
|
||||
this.mode = DEFAULT_FILE_MODE;
|
||||
this.linkFlag = LF_NORMAL;
|
||||
this.size = file.length();
|
||||
}
|
||||
|
||||
this.modTime = file.lastModified() / MILLIS_PER_SECOND;
|
||||
this.devMajor = 0;
|
||||
this.devMinor = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an entry from an archive's header bytes. File is set
|
||||
* to null.
|
||||
*
|
||||
* @param headerBuf The header bytes from a tar archive entry.
|
||||
*/
|
||||
public TarEntry(byte[] headerBuf) {
|
||||
this();
|
||||
parseTarHeader(headerBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the two entries are equal. Equality is determined
|
||||
* by the header names being equal.
|
||||
*
|
||||
* @param it Entry to be checked for equality.
|
||||
* @return True if the entries are equal.
|
||||
*/
|
||||
public boolean equals(TarEntry it) {
|
||||
return getName().equals(it.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the two entries are equal. Equality is determined
|
||||
* by the header names being equal.
|
||||
*
|
||||
* @param it Entry to be checked for equality.
|
||||
* @return True if the entries are equal.
|
||||
*/
|
||||
public boolean equals(Object it) {
|
||||
if (it == null || getClass() != it.getClass()) {
|
||||
return false;
|
||||
}
|
||||
return equals((TarEntry) it);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashcodes are based on entry names.
|
||||
*
|
||||
* @return the entry hashcode
|
||||
*/
|
||||
public int hashCode() {
|
||||
return getName().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given entry is a descendant of this entry.
|
||||
* Descendancy is determined by the name of the descendant
|
||||
* starting with this entry's name.
|
||||
*
|
||||
* @param desc Entry to be checked as a descendent of this.
|
||||
* @return True if entry is a descendant of this.
|
||||
*/
|
||||
public boolean isDescendent(TarEntry desc) {
|
||||
return desc.getName().startsWith(getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's name.
|
||||
*
|
||||
* @return This entry's name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's name.
|
||||
*
|
||||
* @param name This entry's new name.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = new StringBuffer(normalizeFileName(name, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode for this entry
|
||||
*
|
||||
* @param mode the mode for this entry
|
||||
*/
|
||||
public void setMode(int mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's link name.
|
||||
*
|
||||
* @return This entry's link name.
|
||||
*/
|
||||
public String getLinkName() {
|
||||
return linkName.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's user id.
|
||||
*
|
||||
* @return This entry's user id.
|
||||
*/
|
||||
public int getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's user id.
|
||||
*
|
||||
* @param userId This entry's new user id.
|
||||
*/
|
||||
public void setUserId(int userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's group id.
|
||||
*
|
||||
* @return This entry's group id.
|
||||
*/
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's group id.
|
||||
*
|
||||
* @param groupId This entry's new group id.
|
||||
*/
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's user name.
|
||||
*
|
||||
* @return This entry's user name.
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's user name.
|
||||
*
|
||||
* @param userName This entry's new user name.
|
||||
*/
|
||||
public void setUserName(String userName) {
|
||||
this.userName = new StringBuffer(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's group name.
|
||||
*
|
||||
* @return This entry's group name.
|
||||
*/
|
||||
public String getGroupName() {
|
||||
return groupName.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's group name.
|
||||
*
|
||||
* @param groupName This entry's new group name.
|
||||
*/
|
||||
public void setGroupName(String groupName) {
|
||||
this.groupName = new StringBuffer(groupName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to set this entry's group and user ids.
|
||||
*
|
||||
* @param userId This entry's new user id.
|
||||
* @param groupId This entry's new group id.
|
||||
*/
|
||||
public void setIds(int userId, int groupId) {
|
||||
setUserId(userId);
|
||||
setGroupId(groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to set this entry's group and user names.
|
||||
*
|
||||
* @param userName This entry's new user name.
|
||||
* @param groupName This entry's new group name.
|
||||
*/
|
||||
public void setNames(String userName, String groupName) {
|
||||
setUserName(userName);
|
||||
setGroupName(groupName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's modification time. The parameter passed
|
||||
* to this method is in "Java time".
|
||||
*
|
||||
* @param time This entry's new modification time.
|
||||
*/
|
||||
public void setModTime(long time) {
|
||||
modTime = time / MILLIS_PER_SECOND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's modification time.
|
||||
*
|
||||
* @param time This entry's new modification time.
|
||||
*/
|
||||
public void setModTime(Date time) {
|
||||
modTime = time.getTime() / MILLIS_PER_SECOND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's modification time.
|
||||
*
|
||||
* @return time This entry's new modification time.
|
||||
*/
|
||||
public Date getModTime() {
|
||||
return new Date(modTime * MILLIS_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's file.
|
||||
*
|
||||
* @return This entry's file.
|
||||
*/
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's mode.
|
||||
*
|
||||
* @return This entry's mode.
|
||||
*/
|
||||
public int getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this entry's file size.
|
||||
*
|
||||
* @return This entry's file size.
|
||||
*/
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this entry's file size.
|
||||
*
|
||||
* @param size This entry's new file size.
|
||||
*/
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicate if this entry is a GNU long name block
|
||||
*
|
||||
* @return true if this is a long name extension provided by GNU tar
|
||||
*/
|
||||
public boolean isGNULongNameEntry() {
|
||||
return linkFlag == LF_GNUTYPE_LONGNAME
|
||||
&& name.toString().equals(GNU_LONGLINK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not this entry represents a directory.
|
||||
*
|
||||
* @return True if this entry is a directory.
|
||||
*/
|
||||
public boolean isDirectory() {
|
||||
if (file != null) {
|
||||
return file.isDirectory();
|
||||
}
|
||||
|
||||
if (linkFlag == LF_DIR) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getName().endsWith("/")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this entry represents a file, and the file is a directory, return
|
||||
* an array of TarEntries for this entry's children.
|
||||
*
|
||||
* @return An array of TarEntry's for this entry's children.
|
||||
*/
|
||||
public TarEntry[] getDirectoryEntries() {
|
||||
if (file == null || !file.isDirectory()) {
|
||||
return new TarEntry[0];
|
||||
}
|
||||
|
||||
String[] list = file.list();
|
||||
TarEntry[] result = new TarEntry[list.length];
|
||||
|
||||
for (int i = 0; i < list.length; ++i) {
|
||||
result[i] = new TarEntry(new File(file, list[i]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an entry's header information to a header buffer.
|
||||
*
|
||||
* @param outbuf The tar entry header buffer to fill in.
|
||||
*/
|
||||
public void writeEntryHeader(byte[] outbuf) {
|
||||
int offset = 0;
|
||||
|
||||
offset = TarUtils.getNameBytes(name, outbuf, offset, NAMELEN);
|
||||
offset = TarUtils.getOctalBytes(mode, outbuf, offset, MODELEN);
|
||||
offset = TarUtils.getOctalBytes(userId, outbuf, offset, UIDLEN);
|
||||
offset = TarUtils.getOctalBytes(groupId, outbuf, offset, GIDLEN);
|
||||
offset = TarUtils.getLongOctalBytes(size, outbuf, offset, SIZELEN);
|
||||
offset = TarUtils.getLongOctalBytes(modTime, outbuf, offset, MODTIMELEN);
|
||||
|
||||
int csOffset = offset;
|
||||
|
||||
for (int c = 0; c < CHKSUMLEN; ++c) {
|
||||
outbuf[offset++] = (byte) ' ';
|
||||
}
|
||||
|
||||
outbuf[offset++] = linkFlag;
|
||||
offset = TarUtils.getNameBytes(linkName, outbuf, offset, NAMELEN);
|
||||
offset = TarUtils.getNameBytes(magic, outbuf, offset, MAGICLEN);
|
||||
offset = TarUtils.getNameBytes(userName, outbuf, offset, UNAMELEN);
|
||||
offset = TarUtils.getNameBytes(groupName, outbuf, offset, GNAMELEN);
|
||||
offset = TarUtils.getOctalBytes(devMajor, outbuf, offset, DEVLEN);
|
||||
offset = TarUtils.getOctalBytes(devMinor, outbuf, offset, DEVLEN);
|
||||
|
||||
while (offset < outbuf.length) {
|
||||
outbuf[offset++] = 0;
|
||||
}
|
||||
|
||||
long chk = TarUtils.computeCheckSum(outbuf);
|
||||
|
||||
TarUtils.getCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an entry's header information from a header buffer.
|
||||
*
|
||||
* @param header The tar entry header buffer to get information from.
|
||||
*/
|
||||
public void parseTarHeader(byte[] header) {
|
||||
int offset = 0;
|
||||
|
||||
name = TarUtils.parseName(header, offset, NAMELEN);
|
||||
offset += NAMELEN;
|
||||
mode = (int) TarUtils.parseOctal(header, offset, MODELEN);
|
||||
offset += MODELEN;
|
||||
userId = (int) TarUtils.parseOctal(header, offset, UIDLEN);
|
||||
offset += UIDLEN;
|
||||
groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN);
|
||||
offset += GIDLEN;
|
||||
size = TarUtils.parseOctal(header, offset, SIZELEN);
|
||||
offset += SIZELEN;
|
||||
modTime = TarUtils.parseOctal(header, offset, MODTIMELEN);
|
||||
offset += MODTIMELEN;
|
||||
offset += CHKSUMLEN;
|
||||
linkFlag = header[offset++];
|
||||
linkName = TarUtils.parseName(header, offset, NAMELEN);
|
||||
offset += NAMELEN;
|
||||
magic = TarUtils.parseName(header, offset, MAGICLEN);
|
||||
offset += MAGICLEN;
|
||||
userName = TarUtils.parseName(header, offset, UNAMELEN);
|
||||
offset += UNAMELEN;
|
||||
groupName = TarUtils.parseName(header, offset, GNAMELEN);
|
||||
offset += GNAMELEN;
|
||||
devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
|
||||
offset += DEVLEN;
|
||||
devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips Windows' drive letter as well as any leading slashes,
|
||||
* turns path separators into forward slahes.
|
||||
*/
|
||||
private static String normalizeFileName(String fileName,
|
||||
boolean preserveLeadingSlashes) {
|
||||
String osname = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
|
||||
|
||||
if (osname != null) {
|
||||
|
||||
// Strip off drive letters!
|
||||
// REVIEW Would a better check be "(File.separator == '\')"?
|
||||
|
||||
if (osname.startsWith("windows")) {
|
||||
if (fileName.length() > 2) {
|
||||
char ch1 = fileName.charAt(0);
|
||||
char ch2 = fileName.charAt(1);
|
||||
|
||||
if (ch2 == ':'
|
||||
&& ((ch1 >= 'a' && ch1 <= 'z')
|
||||
|| (ch1 >= 'A' && ch1 <= 'Z'))) {
|
||||
fileName = fileName.substring(2);
|
||||
}
|
||||
}
|
||||
} else if (osname.indexOf("netware") > -1) {
|
||||
int colon = fileName.indexOf(':');
|
||||
if (colon != -1) {
|
||||
fileName = fileName.substring(colon + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileName = fileName.replace(File.separatorChar, '/');
|
||||
|
||||
// No absolute pathnames
|
||||
// Windows (and Posix?) paths can start with "\\NetworkDrive\",
|
||||
// so we loop on starting /'s.
|
||||
while (!preserveLeadingSlashes && fileName.startsWith("/")) {
|
||||
fileName = fileName.substring(1);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
package com.intellij.util.io.tar;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* The TarInputStream reads a UNIX tar archive as an InputStream.
|
||||
* methods are provided to position at each successive entry in
|
||||
* the archive, and the read each entry as a normal input stream
|
||||
* using read().
|
||||
*
|
||||
*/
|
||||
// Copy-pasted from org.apache.tools.tar.TarInputStream
|
||||
public class TarInputStream extends FilterInputStream {
|
||||
private static final int SMALL_BUFFER_SIZE = 256;
|
||||
private static final int BUFFER_SIZE = 8 * 1024;
|
||||
private static final int LARGE_BUFFER_SIZE = 32 * 1024;
|
||||
private static final int BYTE_MASK = 0xFF;
|
||||
|
||||
// CheckStyle:VisibilityModifier OFF - bc
|
||||
protected boolean debug;
|
||||
protected boolean hasHitEOF;
|
||||
protected long entrySize;
|
||||
protected long entryOffset;
|
||||
protected byte[] readBuf;
|
||||
protected TarBuffer buffer;
|
||||
protected TarEntry currEntry;
|
||||
|
||||
/**
|
||||
* This contents of this array is not used at all in this class,
|
||||
* it is only here to avoid repreated object creation during calls
|
||||
* to the no-arg read method.
|
||||
*/
|
||||
protected byte[] oneBuf;
|
||||
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
|
||||
/**
|
||||
* Constructor for TarInputStream.
|
||||
* @param is the input stream to use
|
||||
*/
|
||||
public TarInputStream(InputStream is) {
|
||||
this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for TarInputStream.
|
||||
* @param is the input stream to use
|
||||
* @param blockSize the block size to use
|
||||
*/
|
||||
public TarInputStream(InputStream is, int blockSize) {
|
||||
this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for TarInputStream.
|
||||
* @param is the input stream to use
|
||||
* @param blockSize the block size to use
|
||||
* @param recordSize the record size to use
|
||||
*/
|
||||
public TarInputStream(InputStream is, int blockSize, int recordSize) {
|
||||
super(is);
|
||||
|
||||
this.buffer = new TarBuffer(is, blockSize, recordSize);
|
||||
this.readBuf = null;
|
||||
this.oneBuf = new byte[1];
|
||||
this.debug = false;
|
||||
this.hasHitEOF = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the debugging flag.
|
||||
*
|
||||
* @param debug True to turn on debugging.
|
||||
*/
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
buffer.setDebug(debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this stream. Calls the TarBuffer's close() method.
|
||||
* @throws java.io.IOException on error
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
buffer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the record size being used by this stream's TarBuffer.
|
||||
*
|
||||
* @return The TarBuffer record size.
|
||||
*/
|
||||
public int getRecordSize() {
|
||||
return buffer.getRecordSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the available data that can be read from the current
|
||||
* entry in the archive. This does not indicate how much data
|
||||
* is left in the entire archive, only in the current entry.
|
||||
* This value is determined from the entry's size header field
|
||||
* and the amount of data already read from the current entry.
|
||||
* Integer.MAX_VALUE is returen in case more than Integer.MAX_VALUE
|
||||
* bytes are left in the current entry in the archive.
|
||||
*
|
||||
* @return The number of available bytes for the current entry.
|
||||
* @throws IOException for signature
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
if (entrySize - entryOffset > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return (int) (entrySize - entryOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip bytes in the input buffer. This skips bytes in the
|
||||
* current entry's data, not the entire archive, and will
|
||||
* stop at the end of the current entry's data if the number
|
||||
* to skip extends beyond that point.
|
||||
*
|
||||
* @param numToSkip The number of bytes to skip.
|
||||
* @return the number actually skipped
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public long skip(long numToSkip) throws IOException {
|
||||
// REVIEW
|
||||
// This is horribly inefficient, but it ensures that we
|
||||
// properly skip over bytes via the TarBuffer...
|
||||
//
|
||||
byte[] skipBuf = new byte[BUFFER_SIZE];
|
||||
long skip = numToSkip;
|
||||
while (skip > 0) {
|
||||
int realSkip = (int) (skip > skipBuf.length ? skipBuf.length : skip);
|
||||
int numRead = read(skipBuf, 0, realSkip);
|
||||
if (numRead == -1) {
|
||||
break;
|
||||
}
|
||||
skip -= numRead;
|
||||
}
|
||||
return (numToSkip - skip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we do not support marking just yet, we return false.
|
||||
*
|
||||
* @return False.
|
||||
*/
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we do not support marking just yet, we do nothing.
|
||||
*
|
||||
* @param markLimit The limit to mark.
|
||||
*/
|
||||
public void mark(int markLimit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we do not support marking just yet, we do nothing.
|
||||
*/
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next entry in this tar archive. This will skip
|
||||
* over any remaining data in the current entry, if there
|
||||
* is one, and place the input stream at the header of the
|
||||
* next entry, and read the header and instantiate a new
|
||||
* TarEntry from the header bytes and return that entry.
|
||||
* If there are no more entries in the archive, null will
|
||||
* be returned to indicate that the end of the archive has
|
||||
* been reached.
|
||||
*
|
||||
* @return The next TarEntry in the archive, or null.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public TarEntry getNextEntry() throws IOException {
|
||||
if (hasHitEOF) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (currEntry != null) {
|
||||
long numToSkip = entrySize - entryOffset;
|
||||
|
||||
if (debug) {
|
||||
System.err.println("TarInputStream: SKIP currENTRY '"
|
||||
+ currEntry.getName() + "' SZ "
|
||||
+ entrySize + " OFF "
|
||||
+ entryOffset + " skipping "
|
||||
+ numToSkip + " bytes");
|
||||
}
|
||||
|
||||
while (numToSkip > 0) {
|
||||
long skipped = skip(numToSkip);
|
||||
if (skipped <= 0) {
|
||||
throw new RuntimeException("failed to skip current tar"
|
||||
+ " entry");
|
||||
}
|
||||
numToSkip -= skipped;
|
||||
}
|
||||
|
||||
readBuf = null;
|
||||
}
|
||||
|
||||
byte[] headerBuf = buffer.readRecord();
|
||||
|
||||
if (headerBuf == null) {
|
||||
if (debug) {
|
||||
System.err.println("READ NULL RECORD");
|
||||
}
|
||||
hasHitEOF = true;
|
||||
} else if (buffer.isEOFRecord(headerBuf)) {
|
||||
if (debug) {
|
||||
System.err.println("READ EOF RECORD");
|
||||
}
|
||||
hasHitEOF = true;
|
||||
}
|
||||
|
||||
if (hasHitEOF) {
|
||||
currEntry = null;
|
||||
} else {
|
||||
currEntry = new TarEntry(headerBuf);
|
||||
|
||||
if (debug) {
|
||||
System.err.println("TarInputStream: SET CURRENTRY '"
|
||||
+ currEntry.getName()
|
||||
+ "' size = "
|
||||
+ currEntry.getSize());
|
||||
}
|
||||
|
||||
entryOffset = 0;
|
||||
|
||||
entrySize = currEntry.getSize();
|
||||
}
|
||||
|
||||
if (currEntry != null && currEntry.isGNULongNameEntry()) {
|
||||
// read in the name
|
||||
StringBuffer longName = new StringBuffer();
|
||||
byte[] buf = new byte[SMALL_BUFFER_SIZE];
|
||||
int length = 0;
|
||||
while ((length = read(buf)) >= 0) {
|
||||
longName.append(new String(buf, 0, length));
|
||||
}
|
||||
getNextEntry();
|
||||
if (currEntry == null) {
|
||||
// Bugzilla: 40334
|
||||
// Malformed tar file - long entry name not followed by entry
|
||||
return null;
|
||||
}
|
||||
// remove trailing null terminator
|
||||
if (longName.length() > 0
|
||||
&& longName.charAt(longName.length() - 1) == 0) {
|
||||
longName.deleteCharAt(longName.length() - 1);
|
||||
}
|
||||
currEntry.setName(longName.toString());
|
||||
}
|
||||
|
||||
return currEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte from the current tar archive entry.
|
||||
*
|
||||
* This method simply calls read( byte[], int, int ).
|
||||
*
|
||||
* @return The byte read, or -1 at EOF.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
int num = read(oneBuf, 0, 1);
|
||||
return num == -1 ? -1 : ((int) oneBuf[0]) & BYTE_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads bytes from the current tar archive entry.
|
||||
*
|
||||
* This method is aware of the boundaries of the current
|
||||
* entry in the archive and will deal with them as if they
|
||||
* were this stream's start and EOF.
|
||||
*
|
||||
* @param buf The buffer into which to place bytes read.
|
||||
* @param offset The offset at which to place bytes read.
|
||||
* @param numToRead The number of bytes to read.
|
||||
* @return The number of bytes read, or -1 at EOF.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public int read(byte[] buf, int offset, int numToRead) throws IOException {
|
||||
int totalRead = 0;
|
||||
|
||||
if (entryOffset >= entrySize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((numToRead + entryOffset) > entrySize) {
|
||||
numToRead = (int) (entrySize - entryOffset);
|
||||
}
|
||||
|
||||
if (readBuf != null) {
|
||||
int sz = (numToRead > readBuf.length) ? readBuf.length
|
||||
: numToRead;
|
||||
|
||||
System.arraycopy(readBuf, 0, buf, offset, sz);
|
||||
|
||||
if (sz >= readBuf.length) {
|
||||
readBuf = null;
|
||||
} else {
|
||||
int newLen = readBuf.length - sz;
|
||||
byte[] newBuf = new byte[newLen];
|
||||
|
||||
System.arraycopy(readBuf, sz, newBuf, 0, newLen);
|
||||
|
||||
readBuf = newBuf;
|
||||
}
|
||||
|
||||
totalRead += sz;
|
||||
numToRead -= sz;
|
||||
offset += sz;
|
||||
}
|
||||
|
||||
while (numToRead > 0) {
|
||||
byte[] rec = buffer.readRecord();
|
||||
|
||||
if (rec == null) {
|
||||
// Unexpected EOF!
|
||||
throw new IOException("unexpected EOF with " + numToRead
|
||||
+ " bytes unread");
|
||||
}
|
||||
|
||||
int sz = numToRead;
|
||||
int recLen = rec.length;
|
||||
|
||||
if (recLen > sz) {
|
||||
System.arraycopy(rec, 0, buf, offset, sz);
|
||||
|
||||
readBuf = new byte[recLen - sz];
|
||||
|
||||
System.arraycopy(rec, sz, readBuf, 0, recLen - sz);
|
||||
} else {
|
||||
sz = recLen;
|
||||
|
||||
System.arraycopy(rec, 0, buf, offset, recLen);
|
||||
}
|
||||
|
||||
totalRead += sz;
|
||||
numToRead -= sz;
|
||||
offset += sz;
|
||||
}
|
||||
|
||||
entryOffset += totalRead;
|
||||
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of the current tar archive entry directly into
|
||||
* an output stream.
|
||||
*
|
||||
* @param out The OutputStream into which to write the entry's data.
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public void copyEntryContents(OutputStream out) throws IOException {
|
||||
byte[] buf = new byte[LARGE_BUFFER_SIZE];
|
||||
|
||||
while (true) {
|
||||
int numRead = read(buf, 0, buf.length);
|
||||
|
||||
if (numRead == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
out.write(buf, 0, numRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.intellij.util.io.tar;
|
||||
|
||||
/**
|
||||
* This class provides static utility methods to work with byte streams.
|
||||
*
|
||||
*/
|
||||
// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
|
||||
// Copy-pasted from org.apache.tools.tar.TarUtils
|
||||
public class TarUtils {
|
||||
|
||||
private static final int BYTE_MASK = 255;
|
||||
|
||||
/**
|
||||
* Parse an octal string from a header buffer. This is used for the
|
||||
* file permission mode value.
|
||||
*
|
||||
* @param header The header buffer from which to parse.
|
||||
* @param offset The offset into the buffer from which to parse.
|
||||
* @param length The number of header bytes to parse.
|
||||
* @return The long value of the octal string.
|
||||
*/
|
||||
public static long parseOctal(byte[] header, int offset, int length) {
|
||||
long result = 0;
|
||||
boolean stillPadding = true;
|
||||
int end = offset + length;
|
||||
|
||||
for (int i = offset; i < end; ++i) {
|
||||
if (header[i] == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (header[i] == (byte) ' ' || header[i] == '0') {
|
||||
if (stillPadding) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (header[i] == (byte) ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stillPadding = false;
|
||||
// CheckStyle:MagicNumber OFF
|
||||
result = (result << 3) + (header[i] - '0');
|
||||
// CheckStyle:MagicNumber ON
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an entry name from a header buffer.
|
||||
*
|
||||
* @param header The header buffer from which to parse.
|
||||
* @param offset The offset into the buffer from which to parse.
|
||||
* @param length The number of header bytes to parse.
|
||||
* @return The header's entry name.
|
||||
*/
|
||||
public static StringBuffer parseName(byte[] header, int offset, int length) {
|
||||
StringBuffer result = new StringBuffer(length);
|
||||
int end = offset + length;
|
||||
|
||||
for (int i = offset; i < end; ++i) {
|
||||
if (header[i] == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
result.append((char) header[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the number of bytes in an entry name.
|
||||
*
|
||||
* @param name The header name from which to parse.
|
||||
* @param buf The buffer from which to parse.
|
||||
* @param offset The offset into the buffer from which to parse.
|
||||
* @param length The number of header bytes to parse.
|
||||
* @return The number of bytes in a header's entry name.
|
||||
*/
|
||||
public static int getNameBytes(StringBuffer name, byte[] buf, int offset, int length) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length && i < name.length(); ++i) {
|
||||
buf[offset + i] = (byte) name.charAt(i);
|
||||
}
|
||||
|
||||
for (; i < length; ++i) {
|
||||
buf[offset + i] = 0;
|
||||
}
|
||||
|
||||
return offset + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an octal integer from a header buffer.
|
||||
*
|
||||
* @param value The header value
|
||||
* @param buf The buffer from which to parse.
|
||||
* @param offset The offset into the buffer from which to parse.
|
||||
* @param length The number of header bytes to parse.
|
||||
* @return The integer value of the octal bytes.
|
||||
*/
|
||||
public static int getOctalBytes(long value, byte[] buf, int offset, int length) {
|
||||
int idx = length - 1;
|
||||
|
||||
buf[offset + idx] = 0;
|
||||
--idx;
|
||||
buf[offset + idx] = (byte) ' ';
|
||||
--idx;
|
||||
|
||||
if (value == 0) {
|
||||
buf[offset + idx] = (byte) '0';
|
||||
--idx;
|
||||
} else {
|
||||
for (long val = value; idx >= 0 && val > 0; --idx) {
|
||||
// CheckStyle:MagicNumber OFF
|
||||
buf[offset + idx] = (byte) ((byte) '0' + (byte) (val & 7));
|
||||
val = val >> 3;
|
||||
// CheckStyle:MagicNumber ON
|
||||
}
|
||||
}
|
||||
|
||||
for (; idx >= 0; --idx) {
|
||||
buf[offset + idx] = (byte) ' ';
|
||||
}
|
||||
|
||||
return offset + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an octal long integer from a header buffer.
|
||||
*
|
||||
* @param value The header value
|
||||
* @param buf The buffer from which to parse.
|
||||
* @param offset The offset into the buffer from which to parse.
|
||||
* @param length The number of header bytes to parse.
|
||||
* @return The long value of the octal bytes.
|
||||
*/
|
||||
public static int getLongOctalBytes(long value, byte[] buf, int offset, int length) {
|
||||
byte[] temp = new byte[length + 1];
|
||||
|
||||
getOctalBytes(value, temp, 0, length + 1);
|
||||
System.arraycopy(temp, 0, buf, offset, length);
|
||||
|
||||
return offset + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the checksum octal integer from a header buffer.
|
||||
*
|
||||
* @param value The header value
|
||||
* @param buf The buffer from which to parse.
|
||||
* @param offset The offset into the buffer from which to parse.
|
||||
* @param length The number of header bytes to parse.
|
||||
* @return The integer value of the entry's checksum.
|
||||
*/
|
||||
public static int getCheckSumOctalBytes(long value, byte[] buf, int offset, int length) {
|
||||
getOctalBytes(value, buf, offset, length);
|
||||
|
||||
buf[offset + length - 1] = (byte) ' ';
|
||||
buf[offset + length - 2] = 0;
|
||||
|
||||
return offset + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the checksum of a tar entry header.
|
||||
*
|
||||
* @param buf The tar entry's header buffer.
|
||||
* @return The computed checksum.
|
||||
*/
|
||||
public static long computeCheckSum(byte[] buf) {
|
||||
long sum = 0;
|
||||
|
||||
for (int i = 0; i < buf.length; ++i) {
|
||||
sum += BYTE_MASK & buf[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -1331,6 +1331,10 @@
|
||||
<localInspection language="JAVA" shortName="IgnoredJUnitTest" bundle="com.siyeh.InspectionGadgetsBundle" key="ignored.junit.test.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.junit.IgnoredJUnitTestInspection"/>
|
||||
<localInspection language="JAVA" shortName="JUnit3StyleTestMethodInJUnit4Class" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="junit3.style.test.method.in.junit4.class.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.junit.JUnit3StyleTestMethodInJUnit4ClassInspection"/>
|
||||
<localInspection language="JAVA" shortName="JUnit4AnnotatedMethodInJUnit3TestCase" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="junit4.test.method.in.class.extending.junit3.testcase.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.junit.issues" enabledByDefault="true" level="WARNING"
|
||||
|
||||
@@ -1441,6 +1441,7 @@ suspicious.system.arraycopy.problem.descriptor5=<code>#ref</code> is not of an a
|
||||
suspicious.system.arraycopy.problem.descriptor6=Source parameter type ''{0}'' is not assignable to destination parameter <code>#ref</code> of type ''{1}'' #loc
|
||||
raw.use.of.parameterized.type.ignore.new.objects.option=Ignore construction of new objects
|
||||
raw.use.of.parameterized.type.ignore.type.casts.option=Ignore type casts
|
||||
raw.use.of.parameterized.type.ignore.uncompilable.option=Ignore where a type parameter would not compile
|
||||
method.only.used.from.inner.class.display.name=Private method only used from inner class
|
||||
method.only.used.from.inner.class.problem.descriptor.anonymous.extending=Method <code>#ref()</code>#loc is only used from an anonymous class extending ''{0}'' #loc
|
||||
method.only.used.from.inner.class.problem.descriptor.anonymous.implementing=Method <code>#ref()</code>#loc is only used from an anonymous class implementing ''{0}'' #loc
|
||||
@@ -1728,9 +1729,11 @@ redundant.string.format.call.display.name=Redundant call to 'String.format()'
|
||||
redundant.string.format.call.problem.descriptor=Redundant call to <code>#ref</code> #loc
|
||||
redundant.string.format.call.quickfix=Remove redundant call to 'String.format()'
|
||||
junit4.test.method.in.class.extending.junit3.testcase.display.name=JUnit 4 test method in class extending JUnit 3 TestCase
|
||||
junit4.test.method.in.class.extending.junit3.testcase.problem.descriptor=@Test annotated method <code>#ref</code> inside class extending JUnit 3 TestCase #loc
|
||||
ignore.test.method.in.class.extending.junit3.testcase.problem.descriptor=@Ignore annotated method <code>#ref</code> won't be ignored #loc
|
||||
ignore.test.method.in.class.extending.junit3.testcase.problem.fix=Remove @Ignore and rename method to ''{0}''
|
||||
junit4.test.method.in.class.extending.junit3.testcase.problem.descriptor=Method <code>#ref()</code> annotated with '@Test' inside class extending JUnit 3 TestCase #loc
|
||||
ignore.test.method.in.class.extending.junit3.testcase.problem.descriptor=JUnit 3 test method <code>#ref()</code> annotated with '@Ignore' won't be ignored #loc
|
||||
ignore.test.method.in.class.extending.junit3.testcase.quickfix=Remove ''@Ignore'' and rename method to ''{0}''
|
||||
convert.junit3.test.class.quickfix=Convert JUnit 3 class ''{0}'' to JUnit 4
|
||||
remove.junit4.test.annotation.quickfix=Remove '@Test' annotation
|
||||
equals.called.on.enum.constant.display.name='equals()' called on Enum value
|
||||
equals.called.on.enum.constant.problem.descriptor=<code>#ref</code> called on Enum value #loc
|
||||
equals.called.on.enum.constant.quickfix=Replace 'equals()' with '=='
|
||||
@@ -1981,3 +1984,5 @@ public.constructor.display.name='public' constructor
|
||||
public.default.constructor.problem.descriptor=Class <code>#ref</code> has public default constructor
|
||||
public.constructor.problem.descriptor=Public constructor <code>#ref()</code>
|
||||
public.constructor.quickfix=Replace constructor with factory method
|
||||
junit3.style.test.method.in.junit4.class.display.name=Old style JUnit test method in JUnit 4 class
|
||||
junit3.style.test.method.in.junit4.class.problem.descriptor=Old style JUnit test method <code>#ref</code> in JUnit 4 class
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2009 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,8 @@ package com.siyeh.ig.fixes;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.AsyncResult;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.refactoring.RefactoringFactory;
|
||||
import com.intellij.refactoring.RenameRefactoring;
|
||||
@@ -51,14 +51,14 @@ public class RenameFix extends InspectionGadgetsFix {
|
||||
m_searchInNonJavaFiles = searchInNonJavaFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
if (m_targetName == null) {
|
||||
return InspectionGadgetsBundle.message("rename.quickfix");
|
||||
}
|
||||
else {
|
||||
return InspectionGadgetsBundle.message("renameto.quickfix",
|
||||
m_targetName);
|
||||
return InspectionGadgetsBundle.message("renameto.quickfix", m_targetName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,30 +67,24 @@ public class RenameFix extends InspectionGadgetsFix {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(final Project project, ProblemDescriptor descriptor) {
|
||||
public void doFix(final Project project, final ProblemDescriptor descriptor) {
|
||||
final PsiElement nameIdentifier = descriptor.getPsiElement();
|
||||
final PsiElement elementToRename = nameIdentifier.getParent();
|
||||
if (m_targetName == null) {
|
||||
final DataManager dataManager = DataManager.getInstance();
|
||||
final DataContext dataContext = dataManager.getDataContext();
|
||||
final RenameHandler renameHandler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext);
|
||||
if (renameHandler == null) return;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
renameHandler.invoke(project, new PsiElement[]{elementToRename},
|
||||
dataContext);
|
||||
final AsyncResult<DataContext> contextFromFocus = DataManager.getInstance().getDataContextFromFocus();
|
||||
contextFromFocus.doWhenDone(new AsyncResult.Handler<DataContext>() {
|
||||
@Override
|
||||
public void run(DataContext context) {
|
||||
final RenameHandler renameHandler = RenameHandlerRegistry.getInstance().getRenameHandler(context);
|
||||
if (renameHandler == null) {
|
||||
return;
|
||||
}
|
||||
renameHandler.invoke(project, new PsiElement[]{elementToRename}, context);
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
runnable.run();
|
||||
}
|
||||
else {
|
||||
ApplicationManager.getApplication().invokeLater(runnable, project.getDisposed());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
final RefactoringFactory factory =
|
||||
RefactoringFactory.getInstance(project);
|
||||
final RefactoringFactory factory = RefactoringFactory.getInstance(project);
|
||||
final RenameRefactoring renameRefactoring =
|
||||
factory.createRename(elementToRename, m_targetName, m_searchInStrings, m_searchInNonJavaFiles);
|
||||
renameRefactoring.run();
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.junit;
|
||||
|
||||
import com.intellij.codeInspection.AnnotateMethodFix;
|
||||
import com.intellij.psi.*;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.DelegatingFix;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.psiutils.ImportUtils;
|
||||
import com.siyeh.ig.psiutils.TestUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class JUnit3StyleTestMethodInJUnit4ClassInspection extends BaseInspection {
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("junit3.style.test.method.in.junit4.class.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("junit3.style.test.method.in.junit4.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new DelegatingFix(new AnnotateMethodFix("org.junit.Test"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new JUnit3StyleTestMethodInJUnit4ClassInspectionVisitor();
|
||||
}
|
||||
|
||||
private static class JUnit3StyleTestMethodInJUnit4ClassInspectionVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
final String name = method.getName();
|
||||
if (!name.startsWith("test")) {
|
||||
return;
|
||||
}
|
||||
if (method.hasModifierProperty(PsiModifier.ABSTRACT) || !method.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return;
|
||||
}
|
||||
if (TestUtils.isJUnit4TestMethod(method)) {
|
||||
return;
|
||||
}
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (returnType == null || !returnType.equals(PsiType.VOID)) {
|
||||
return;
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (parameterList.getParametersCount() != 0) {
|
||||
return;
|
||||
}
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
if (TestUtils.isJUnitTestClass(containingClass)) {
|
||||
return;
|
||||
}
|
||||
if (!ImportUtils.containsReferenceToClass(containingClass, "org.junit.Test")) {
|
||||
return;
|
||||
}
|
||||
registerMethodError(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
+145
-68
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2009 Bas Leijdekkers
|
||||
* Copyright 2008-2012 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,7 @@ import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
@@ -30,8 +30,10 @@ import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
BaseInspection {
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends BaseInspection {
|
||||
|
||||
private static final String IGNORE = "org.junit.Ignore";
|
||||
|
||||
@@ -39,20 +41,16 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
@Nls
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"junit4.test.method.in.class.extending.junit3.testcase.display.name");
|
||||
return InspectionGadgetsBundle.message("junit4.test.method.in.class.extending.junit3.testcase.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
|
||||
if (infos[0] instanceof PsiMethod &&
|
||||
AnnotationUtil.isAnnotated((PsiModifierListOwner)infos[0], IGNORE, false)) {
|
||||
if (AnnotationUtil.isAnnotated((PsiMethod)infos[1], IGNORE, false)) {
|
||||
return InspectionGadgetsBundle.message("ignore.test.method.in.class.extending.junit3.testcase.problem.descriptor");
|
||||
}
|
||||
return InspectionGadgetsBundle.message(
|
||||
"junit4.test.method.in.class.extending.junit3.testcase.problem.descriptor");
|
||||
return InspectionGadgetsBundle.message("junit4.test.method.in.class.extending.junit3.testcase.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,39 +61,18 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
@NotNull
|
||||
@Override
|
||||
protected InspectionGadgetsFix[] buildFixes(Object... infos) {
|
||||
String className = null;
|
||||
if (infos[0] instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)infos[0];
|
||||
PsiClass containingClass = method.getContainingClass();
|
||||
if (containingClass == null) return InspectionGadgetsFix.EMPTY_ARRAY;
|
||||
className = containingClass.getName();
|
||||
if (AnnotationUtil.isAnnotated(method, IGNORE, false)) {
|
||||
if (!TestUtils.isJUnit4TestMethod(method)) {
|
||||
return new InspectionGadgetsFix[]{new RemoveIgnoreAndRename(method),
|
||||
new RemoveExtendsTestCaseFix(className)};
|
||||
}
|
||||
else {
|
||||
return new InspectionGadgetsFix[]{new RemoveIgnoreAndRename(method),
|
||||
new RemoveTestAnnotationFix(),
|
||||
new RemoveExtendsTestCaseFix(className)};
|
||||
}
|
||||
}
|
||||
final List<InspectionGadgetsFix> fixes = new ArrayList(3);
|
||||
final PsiMethod method = (PsiMethod)infos[1];
|
||||
if (AnnotationUtil.isAnnotated(method, IGNORE, false)) {
|
||||
fixes.add(new RemoveIgnoreAndRename(method));
|
||||
}
|
||||
|
||||
if (className == null) {
|
||||
className = (String)infos[0];
|
||||
}
|
||||
if (className != null) {
|
||||
return new InspectionGadgetsFix[]{
|
||||
new RemoveTestAnnotationFix(),
|
||||
new RemoveExtendsTestCaseFix(className)
|
||||
};
|
||||
}
|
||||
else {
|
||||
return new InspectionGadgetsFix[]{
|
||||
new RemoveTestAnnotationFix()
|
||||
};
|
||||
if (TestUtils.isJUnit4TestMethod(method)) {
|
||||
fixes.add(new RemoveTestAnnotationFix());
|
||||
}
|
||||
final PsiClass aClass = (PsiClass)infos[0];
|
||||
final String className = aClass.getName();
|
||||
fixes.add(new ConvertToJUnit4Fix(className));
|
||||
return fixes.toArray(new InspectionGadgetsFix[fixes.size()]);
|
||||
}
|
||||
|
||||
private static void deleteAnnotation(ProblemDescriptor descriptor, final String qualifiedName) {
|
||||
@@ -117,6 +94,7 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
}
|
||||
|
||||
private static class RemoveIgnoreAndRename extends RenameFix {
|
||||
|
||||
public RemoveIgnoreAndRename(@NonNls PsiMethod method) {
|
||||
super("_" + method.getName());
|
||||
}
|
||||
@@ -124,7 +102,7 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("ignore.test.method.in.class.extending.junit3.testcase.problem.fix", getTargetName());
|
||||
return InspectionGadgetsBundle.message("ignore.test.method.in.class.extending.junit3.testcase.quickfix", getTargetName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,53 +112,157 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConvertToJUnit4Fix extends InspectionGadgetsFix {
|
||||
|
||||
private static class RemoveExtendsTestCaseFix extends InspectionGadgetsFix {
|
||||
private final String className;
|
||||
|
||||
RemoveExtendsTestCaseFix(String className) {
|
||||
ConvertToJUnit4Fix(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "remove 'extends TestCase' from class '" + className + '\'';
|
||||
return InspectionGadgetsBundle.message("convert.junit3.test.class.quickfix", className);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor)
|
||||
throws IncorrectOperationException {
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
final PsiElement parent = element.getParent();
|
||||
if (!(parent instanceof PsiMember)) {
|
||||
return;
|
||||
}
|
||||
final PsiMember method = (PsiMember)parent;
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
final PsiMember member = (PsiMember)parent;
|
||||
final PsiClass containingClass = member.getContainingClass();
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
}
|
||||
final PsiReferenceList extendsList =
|
||||
containingClass.getExtendsList();
|
||||
final PsiReferenceList extendsList = containingClass.getExtendsList();
|
||||
if (extendsList == null) {
|
||||
return;
|
||||
}
|
||||
extendsList.delete();
|
||||
final PsiMethod[] methods = containingClass.getMethods();
|
||||
for (PsiMethod method : methods) {
|
||||
@NonNls final String name = method.getName();
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
continue;
|
||||
}
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (!PsiType.VOID.equals(returnType)) {
|
||||
continue;
|
||||
}
|
||||
final PsiModifierList modifierList = method.getModifierList();
|
||||
if (name.startsWith("test")) {
|
||||
addAnnotationIfNotPresent(modifierList, "org.junit.Test");
|
||||
}
|
||||
else if (name.equals("setUp")) {
|
||||
transformSetUpOrTearDownMethod(method);
|
||||
addAnnotationIfNotPresent(modifierList, "org.junit.Before");
|
||||
}
|
||||
else if (name.equals("tearDown")) {
|
||||
transformSetUpOrTearDownMethod(method);
|
||||
addAnnotationIfNotPresent(modifierList, "org.junit.After");
|
||||
}
|
||||
method.accept(new MethodCallModifier());
|
||||
}
|
||||
final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
|
||||
for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
|
||||
referenceElement.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAnnotationIfNotPresent(PsiModifierList modifierList, String qualifiedAnnotationName) {
|
||||
if (modifierList.findAnnotation(qualifiedAnnotationName) != null) {
|
||||
return;
|
||||
}
|
||||
final PsiAnnotation annotation = modifierList.addAnnotation(qualifiedAnnotationName);
|
||||
final Project project = modifierList.getProject();
|
||||
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
codeStyleManager.shortenClassReferences(annotation);
|
||||
}
|
||||
|
||||
private static void transformSetUpOrTearDownMethod(PsiMethod method) {
|
||||
final PsiModifierList modifierList = method.getModifierList();
|
||||
if (modifierList.hasModifierProperty(PsiModifier.PROTECTED)) {
|
||||
modifierList.setModifierProperty(PsiModifier.PROTECTED, false);
|
||||
}
|
||||
if (!modifierList.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
modifierList.setModifierProperty(PsiModifier.PUBLIC, true);
|
||||
}
|
||||
final PsiAnnotation overrideAnnotation = modifierList.findAnnotation("java.lang.Override");
|
||||
if (overrideAnnotation != null) {
|
||||
overrideAnnotation.delete();
|
||||
}
|
||||
method.accept(new SuperLifeCycleCallRemover(method.getName()));
|
||||
}
|
||||
|
||||
private static class SuperLifeCycleCallRemover extends JavaRecursiveElementVisitor {
|
||||
|
||||
@NotNull private final String myLifeCycleMethodName;
|
||||
|
||||
private SuperLifeCycleCallRemover(@NotNull String lifeCycleMethodName) {
|
||||
myLifeCycleMethodName = lifeCycleMethodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
final String methodName = methodExpression.getReferenceName();
|
||||
if (!myLifeCycleMethodName.equals(methodName)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression target = methodExpression.getQualifierExpression();
|
||||
if (!(target instanceof PsiSuperExpression)) {
|
||||
return;
|
||||
}
|
||||
expression.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MethodCallModifier extends JavaRecursiveElementVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
if (methodExpression.getQualifierExpression() != null) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod method = expression.resolveMethod();
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
final PsiClass aClass = method.getContainingClass();
|
||||
if (aClass == null) {
|
||||
return;
|
||||
}
|
||||
final String name = aClass.getQualifiedName();
|
||||
if (!"junit.framework.Assert".equals(name)) {
|
||||
return;
|
||||
}
|
||||
@NonNls final String newExpressionText = "org.junit.Assert." + expression.getText();
|
||||
final Project project = expression.getProject();
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
final PsiExpression newExpression = factory.createExpressionFromText(newExpressionText, expression);
|
||||
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
final PsiElement replacedExpression = expression.replace(newExpression);
|
||||
codeStyleManager.shortenClassReferences(replacedExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class RemoveTestAnnotationFix extends InspectionGadgetsFix {
|
||||
|
||||
private static class RemoveTestAnnotationFix
|
||||
extends InspectionGadgetsFix {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Remove @Test annotation";
|
||||
return InspectionGadgetsBundle.message("remove.junit4.test.annotation.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor)
|
||||
throws IncorrectOperationException {
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor) {
|
||||
deleteAnnotation(descriptor, "org.junit.Test");
|
||||
}
|
||||
}
|
||||
@@ -190,8 +272,7 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
return new Junit4AnnotatedMethodInJunit3TestCaseVisitor();
|
||||
}
|
||||
|
||||
private static class Junit4AnnotatedMethodInJunit3TestCaseVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
private static class Junit4AnnotatedMethodInJunit3TestCaseVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
@@ -204,14 +285,10 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends
|
||||
return;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(method, IGNORE, false) && method.getName().startsWith("test")) {
|
||||
registerMethodError(method, method);
|
||||
return;
|
||||
registerMethodError(method, containingClass, method);
|
||||
} else if (TestUtils.isJUnit4TestMethod(method)) {
|
||||
registerMethodError(method, containingClass, method);
|
||||
}
|
||||
if (!TestUtils.isJUnit4TestMethod(method)) {
|
||||
return;
|
||||
}
|
||||
final String className = containingClass.getName();
|
||||
registerMethodError(method, className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,8 +32,7 @@ import java.util.List;
|
||||
|
||||
public class ImportUtils {
|
||||
|
||||
private ImportUtils() {
|
||||
}
|
||||
private ImportUtils() {}
|
||||
|
||||
public static void addImportIfNeeded(@NotNull PsiClass aClass,
|
||||
@NotNull PsiElement context) {
|
||||
@@ -302,10 +301,10 @@ public class ImportUtils {
|
||||
return true;
|
||||
}
|
||||
final String qualifiedClassName = aClass.getQualifiedName();
|
||||
final ClassReferenceVisitor visitor =
|
||||
new ClassReferenceVisitor(qualifiedClassName);
|
||||
file.accept(visitor);
|
||||
return visitor.isReferenceFound();
|
||||
if (fqName.equals(qualifiedClassName)) {
|
||||
continue;
|
||||
}
|
||||
return containsReferenceToClass(file, qualifiedClassName);
|
||||
}
|
||||
}
|
||||
return hasJavaLangImportConflict(fqName, file);
|
||||
@@ -411,19 +410,15 @@ public class ImportUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean containsConflictingClass(String fqName,
|
||||
PsiJavaFile file) {
|
||||
private static boolean containsConflictingClass(String fqName, PsiJavaFile file) {
|
||||
final PsiClass[] classes = file.getClasses();
|
||||
for (PsiClass aClass : classes) {
|
||||
if (containsConflictingInnerClass(fqName, aClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//return false;
|
||||
final ClassReferenceVisitor visitor =
|
||||
new ClassReferenceVisitor(fqName);
|
||||
file.accept(visitor);
|
||||
return visitor.isReferenceFound();
|
||||
return false;
|
||||
//return containsReferenceToClass(file, fqName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -646,8 +641,13 @@ public class ImportUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClassReferenceVisitor
|
||||
extends JavaRecursiveElementVisitor {
|
||||
public static boolean containsReferenceToClass(PsiElement element, String fullyQualifiedName) {
|
||||
final ClassReferenceVisitor visitor = new ClassReferenceVisitor(fullyQualifiedName);
|
||||
element.accept(visitor);
|
||||
return visitor.isReferenceFound();
|
||||
}
|
||||
|
||||
private static class ClassReferenceVisitor extends JavaRecursiveElementVisitor {
|
||||
|
||||
private final String name;
|
||||
private final String fullyQualifiedName;
|
||||
@@ -659,8 +659,7 @@ public class ImportUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceElement(
|
||||
PsiJavaCodeReferenceElement reference) {
|
||||
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
if (referenceFound) {
|
||||
return;
|
||||
@@ -670,16 +669,14 @@ public class ImportUtils {
|
||||
return;
|
||||
}
|
||||
final PsiElement element = reference.resolve();
|
||||
if (!(element instanceof PsiClass)
|
||||
|| element instanceof PsiTypeParameter) {
|
||||
if (!(element instanceof PsiClass) || element instanceof PsiTypeParameter) {
|
||||
return;
|
||||
}
|
||||
final PsiClass aClass = (PsiClass)element;
|
||||
final String testClassName = aClass.getName();
|
||||
final String testClassQualifiedName = aClass.getQualifiedName();
|
||||
if (testClassQualifiedName == null || testClassName == null
|
||||
|| testClassQualifiedName.equals(fullyQualifiedName) ||
|
||||
!testClassName.equals(name)) {
|
||||
|| !testClassQualifiedName.equals(fullyQualifiedName) || !testClassName.equals(name)) {
|
||||
return;
|
||||
}
|
||||
referenceFound = true;
|
||||
|
||||
+23
-29
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,34 +36,29 @@ public class UnnecessaryParenthesesInspection extends BaseInspection {
|
||||
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public boolean ignoreParenthesesOnConditionals = false;
|
||||
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean ignoreParenthesesOnLambdaParameter = false;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"unnecessary.parentheses.display.name");
|
||||
return InspectionGadgetsBundle.message("unnecessary.parentheses.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"unnecessary.parentheses.problem.descriptor");
|
||||
return InspectionGadgetsBundle.message("unnecessary.parentheses.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
final MultipleCheckboxOptionsPanel optionsPanel =
|
||||
new MultipleCheckboxOptionsPanel(this);
|
||||
optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
|
||||
"unnecessary.parentheses.option"),
|
||||
"ignoreClarifyingParentheses");
|
||||
optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
|
||||
"unnecessary.parentheses.conditional.option"),
|
||||
final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this);
|
||||
optionsPanel.addCheckbox(InspectionGadgetsBundle.message("unnecessary.parentheses.option"), "ignoreClarifyingParentheses");
|
||||
optionsPanel.addCheckbox(InspectionGadgetsBundle.message("unnecessary.parentheses.conditional.option"),
|
||||
"ignoreParenthesesOnConditionals");
|
||||
optionsPanel.addCheckbox("Ignore parentheses around single no formal type lambda parameter",
|
||||
"ignoreParenthesesOnLambdaParameter");
|
||||
optionsPanel.addCheckbox("Ignore parentheses around single no formal type lambda parameter", "ignoreParenthesesOnLambdaParameter");
|
||||
return optionsPanel;
|
||||
}
|
||||
|
||||
@@ -112,26 +107,28 @@ public class UnnecessaryParenthesesInspection extends BaseInspection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParenthesizedExpression(
|
||||
PsiParenthesizedExpression expression) {
|
||||
public void visitParenthesizedExpression(PsiParenthesizedExpression expression) {
|
||||
final PsiElement parent = expression.getParent();
|
||||
final PsiExpression child = expression.getExpression();
|
||||
if (child == null) {
|
||||
return;
|
||||
}
|
||||
if (!(parent instanceof PsiExpression) ||
|
||||
parent instanceof PsiParenthesizedExpression) {
|
||||
if (!(parent instanceof PsiExpression) || parent instanceof PsiParenthesizedExpression) {
|
||||
registerError(expression);
|
||||
return;
|
||||
}
|
||||
final int parentPrecedence =
|
||||
ParenthesesUtils.getPrecedence((PsiExpression)parent);
|
||||
final int parentPrecedence = ParenthesesUtils.getPrecedence((PsiExpression)parent);
|
||||
final int childPrecedence = ParenthesesUtils.getPrecedence(child);
|
||||
if (parentPrecedence > childPrecedence) {
|
||||
if (ignoreClarifyingParentheses) {
|
||||
if (parent instanceof PsiPolyadicExpression &&
|
||||
child instanceof PsiPolyadicExpression) {
|
||||
return;
|
||||
if (child instanceof PsiPolyadicExpression) {
|
||||
if (parent instanceof PsiPolyadicExpression) {
|
||||
return;
|
||||
} else if (parent instanceof PsiConditionalExpression) {
|
||||
return;
|
||||
} else if (parent instanceof PsiInstanceOfExpression) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (child instanceof PsiInstanceOfExpression) {
|
||||
return;
|
||||
@@ -139,10 +136,8 @@ public class UnnecessaryParenthesesInspection extends BaseInspection {
|
||||
}
|
||||
if (ignoreParenthesesOnConditionals) {
|
||||
if (parent instanceof PsiConditionalExpression) {
|
||||
final PsiConditionalExpression conditionalExpression =
|
||||
(PsiConditionalExpression)parent;
|
||||
final PsiExpression condition =
|
||||
conditionalExpression.getCondition();
|
||||
final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)parent;
|
||||
final PsiExpression condition = conditionalExpression.getCondition();
|
||||
if (expression == condition) {
|
||||
return;
|
||||
}
|
||||
@@ -152,8 +147,7 @@ public class UnnecessaryParenthesesInspection extends BaseInspection {
|
||||
return;
|
||||
}
|
||||
if (parentPrecedence == childPrecedence) {
|
||||
if (!ParenthesesUtils.areParenthesesNeeded(expression,
|
||||
ignoreClarifyingParentheses)) {
|
||||
if (!ParenthesesUtils.areParenthesesNeeded(expression, ignoreClarifyingParentheses)) {
|
||||
registerError(expression);
|
||||
return;
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports JUnit 3 style test methods which are located inside a class
|
||||
which does not extend the abstract JUnit 3 class <b>TestCase</b> and contains JUnit 4 <b>@Test</b> annotated methods.
|
||||
In addition to being confusing such test methods will not be run.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
<small>New in 12, Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
</html>
|
||||
+4
-3
@@ -1,8 +1,9 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports JUnit 4 @Test annotated methods which are located inside a class
|
||||
extending the abstract JUnit 3 class TestCase. Mixing JUnit API's like this is
|
||||
confusing and can lead to problems running the tests, e.g. method annotated with @Ignore won't be actually ignored if its name starts with test
|
||||
This inspection reports JUnit 4 <b>@Test</b> annotated methods which are located inside a class
|
||||
extending the abstract JUnit 3 class <b>TestCase</b>. Mixing JUnit API's like this is
|
||||
confusing and can lead to problems running the tests, for example a method annotated with <b>@Ignore</b> won't
|
||||
be actually ignored if its name starts with test.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
<small>Powered by InspectionGadgets</small>
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.siyeh.igtest.style.clarifying_parentheses;
|
||||
|
||||
class UnnecessaryParentheses {
|
||||
|
||||
String oldValue;
|
||||
boolean update(UnnecessaryParentheses that) {
|
||||
final boolean c = ("" + "asdf") instanceof String;
|
||||
boolean b = true && (that instanceof Object);
|
||||
if ((oldValue != null) ? !oldValue.equals(that.oldValue) : (that.oldValue != null)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
|
||||
</problems>
|
||||
+7
-2
@@ -8,8 +8,7 @@ import com.siyeh.ig.IGInspectionTestCase;
|
||||
public class UnnecessaryParenthesesInspectionTest extends IGInspectionTestCase {
|
||||
|
||||
public void test() throws Exception {
|
||||
final UnnecessaryParenthesesInspection inspection =
|
||||
new UnnecessaryParenthesesInspection();
|
||||
final UnnecessaryParenthesesInspection inspection = new UnnecessaryParenthesesInspection();
|
||||
inspection.ignoreParenthesesOnConditionals = true;
|
||||
final LanguageLevelProjectExtension levelProjectExtension = LanguageLevelProjectExtension.getInstance(getProject());
|
||||
final LanguageLevel level = levelProjectExtension.getLanguageLevel();
|
||||
@@ -22,4 +21,10 @@ public class UnnecessaryParenthesesInspectionTest extends IGInspectionTestCase {
|
||||
levelProjectExtension.setLanguageLevel(level);
|
||||
}
|
||||
}
|
||||
|
||||
public void testClarifyingParentheses() {
|
||||
final UnnecessaryParenthesesInspection inspection = new UnnecessaryParenthesesInspection();
|
||||
inspection.ignoreClarifyingParentheses = true;
|
||||
doTest("com/siyeh/igtest/style/clarifying_parentheses", inspection);
|
||||
}
|
||||
}
|
||||
+21
-40
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009 Bas Leijdekkers
|
||||
* Copyright 2009-2012 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.ipp.base.Intention;
|
||||
import com.siyeh.ipp.base.PsiElementPredicate;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
@@ -32,8 +33,7 @@ public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processIntention(@NotNull PsiElement element)
|
||||
throws IncorrectOperationException {
|
||||
protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (!(parent instanceof PsiClass)) {
|
||||
return;
|
||||
@@ -45,7 +45,7 @@ public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
}
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
for (PsiMethod method : methods) {
|
||||
final String name = method.getName();
|
||||
@NonNls final String name = method.getName();
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
continue;
|
||||
}
|
||||
@@ -67,23 +67,19 @@ public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
}
|
||||
method.accept(new MethodCallModifier());
|
||||
}
|
||||
final PsiJavaCodeReferenceElement[] referenceElements =
|
||||
extendsList.getReferenceElements();
|
||||
final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
|
||||
for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
|
||||
referenceElement.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAnnotationIfNotPresent(
|
||||
PsiModifierList modifierList, String qualifiedAnnotationName) {
|
||||
private static void addAnnotationIfNotPresent(PsiModifierList modifierList, String qualifiedAnnotationName) {
|
||||
if (modifierList.findAnnotation(qualifiedAnnotationName) != null) {
|
||||
return;
|
||||
}
|
||||
final PsiAnnotation annotation =
|
||||
modifierList.addAnnotation(qualifiedAnnotationName);
|
||||
final PsiAnnotation annotation = modifierList.addAnnotation(qualifiedAnnotationName);
|
||||
final Project project = modifierList.getProject();
|
||||
final JavaCodeStyleManager codeStyleManager =
|
||||
JavaCodeStyleManager.getInstance(project);
|
||||
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
codeStyleManager.shortenClassReferences(annotation);
|
||||
}
|
||||
|
||||
@@ -95,17 +91,14 @@ public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
if (!modifierList.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
modifierList.setModifierProperty(PsiModifier.PUBLIC, true);
|
||||
}
|
||||
final PsiAnnotation overrideAnnotation =
|
||||
modifierList.findAnnotation("java.lang.Override");
|
||||
final PsiAnnotation overrideAnnotation = modifierList.findAnnotation("java.lang.Override");
|
||||
if (overrideAnnotation != null) {
|
||||
overrideAnnotation.delete();
|
||||
}
|
||||
|
||||
method.accept(new SuperLifeCycleCallRemover(method.getName()));
|
||||
}
|
||||
|
||||
private static class SuperLifeCycleCallRemover
|
||||
extends JavaRecursiveElementVisitor {
|
||||
private static class SuperLifeCycleCallRemover extends JavaRecursiveElementVisitor {
|
||||
|
||||
@NotNull private final String myLifeCycleMethodName;
|
||||
|
||||
@@ -114,17 +107,14 @@ public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(
|
||||
PsiMethodCallExpression expression) {
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
final PsiReferenceExpression methodExpression =
|
||||
expression.getMethodExpression();
|
||||
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
final String methodName = methodExpression.getReferenceName();
|
||||
if (!myLifeCycleMethodName.equals(methodName)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression target =
|
||||
methodExpression.getQualifierExpression();
|
||||
final PsiExpression target = methodExpression.getQualifierExpression();
|
||||
if (!(target instanceof PsiSuperExpression)) {
|
||||
return;
|
||||
}
|
||||
@@ -132,15 +122,12 @@ public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
}
|
||||
}
|
||||
|
||||
private static class MethodCallModifier
|
||||
extends JavaRecursiveElementVisitor {
|
||||
private static class MethodCallModifier extends JavaRecursiveElementVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(
|
||||
PsiMethodCallExpression expression) {
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
final PsiReferenceExpression methodExpression =
|
||||
expression.getMethodExpression();
|
||||
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
if (methodExpression.getQualifierExpression() != null) {
|
||||
return;
|
||||
}
|
||||
@@ -156,18 +143,12 @@ public class ConvertJUnit3TestCaseToJUnit4Intention extends Intention {
|
||||
if (!"junit.framework.Assert".equals(name)) {
|
||||
return;
|
||||
}
|
||||
final String newExpressionText =
|
||||
"org.junit.Assert." + expression.getText();
|
||||
@NonNls final String newExpressionText = "org.junit.Assert." + expression.getText();
|
||||
final Project project = expression.getProject();
|
||||
final PsiElementFactory factory =
|
||||
JavaPsiFacade.getElementFactory(project);
|
||||
final PsiExpression newExpression =
|
||||
factory.createExpressionFromText(newExpressionText,
|
||||
expression);
|
||||
final JavaCodeStyleManager codeStyleManager =
|
||||
JavaCodeStyleManager.getInstance(project);
|
||||
final PsiElement replacedExpression =
|
||||
expression.replace(newExpression);
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
final PsiExpression newExpression = factory.createExpressionFromText(newExpressionText, expression);
|
||||
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
final PsiElement replacedExpression = expression.replace(newExpression);
|
||||
codeStyleManager.shortenClassReferences(replacedExpression);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009 Bas Leijdekkers
|
||||
* Copyright 2009-2012 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,9 +20,9 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.siyeh.ipp.base.PsiElementPredicate;
|
||||
|
||||
public class ConvertJUnit3TestCaseToJUnit4Predicate
|
||||
implements PsiElementPredicate {
|
||||
class ConvertJUnit3TestCaseToJUnit4Predicate implements PsiElementPredicate {
|
||||
|
||||
@Override
|
||||
public boolean satisfiedBy(PsiElement element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (!(parent instanceof PsiClass)) {
|
||||
@@ -31,21 +31,18 @@ public class ConvertJUnit3TestCaseToJUnit4Predicate
|
||||
final PsiClass aClass = (PsiClass)parent;
|
||||
final PsiElement leftBrace = aClass.getLBrace();
|
||||
final int offsetInParent = element.getStartOffsetInParent();
|
||||
if (leftBrace == null ||
|
||||
offsetInParent >= leftBrace.getStartOffsetInParent()) {
|
||||
if (leftBrace == null || offsetInParent >= leftBrace.getStartOffsetInParent()) {
|
||||
return false;
|
||||
}
|
||||
final PsiReferenceList extendsList = aClass.getExtendsList();
|
||||
if (extendsList == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiJavaCodeReferenceElement[] referenceElements =
|
||||
extendsList.getReferenceElements();
|
||||
final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
|
||||
if (referenceElements.length != 1) {
|
||||
return false;
|
||||
}
|
||||
final PsiJavaCodeReferenceElement referenceElement =
|
||||
referenceElements[0];
|
||||
final PsiJavaCodeReferenceElement referenceElement = referenceElements[0];
|
||||
final PsiElement target = referenceElement.resolve();
|
||||
if (!(target instanceof PsiClass)) {
|
||||
return false;
|
||||
@@ -58,8 +55,7 @@ public class ConvertJUnit3TestCaseToJUnit4Predicate
|
||||
final Project project = element.getProject();
|
||||
final GlobalSearchScope scope = element.getResolveScope();
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
final PsiClass testAnnotation =
|
||||
psiFacade.findClass("org.junit.Test", scope);
|
||||
final PsiClass testAnnotation = psiFacade.findClass("org.junit.Test", scope);
|
||||
return testAnnotation != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package com.intellij.spellchecker.inspections;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -24,6 +27,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.text.CharacterIterator;
|
||||
import java.text.StringCharacterIterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -31,7 +35,10 @@ import java.util.regex.Pattern;
|
||||
|
||||
public abstract class BaseSplitter implements Splitter {
|
||||
|
||||
static final Logger LOG = Logger.getInstance("#com.intellij.spellchecker.inspections.BaseSplitter");
|
||||
|
||||
public static final int MIN_RANGE_LENGTH = 3;
|
||||
public static final int MAX_RANGE_LENGTH = 50;
|
||||
|
||||
|
||||
protected static void addWord(@NotNull Consumer<TextRange> consumer, boolean ignore, @Nullable TextRange found) {
|
||||
@@ -83,8 +90,9 @@ public abstract class BaseSplitter implements Splitter {
|
||||
return TextRange.from(range.getStartOffset() + start, end - start);
|
||||
}
|
||||
|
||||
protected static boolean tooSmall(int from, int till) {
|
||||
return till - from <= MIN_RANGE_LENGTH;
|
||||
protected static boolean badSize(int from, int till) {
|
||||
int l = till - from;
|
||||
return l <= MIN_RANGE_LENGTH || l>= MAX_RANGE_LENGTH;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -93,35 +101,40 @@ public abstract class BaseSplitter implements Splitter {
|
||||
int from = range.getStartOffset();
|
||||
int till;
|
||||
boolean addLast = true;
|
||||
Matcher matcher = toExclude.matcher(range.substring(text));
|
||||
while (matcher.find()) {
|
||||
|
||||
checkCancelled();
|
||||
|
||||
TextRange found = matcherRange(range, matcher);
|
||||
till = found.getStartOffset() - 1;
|
||||
if (range.getEndOffset() - found.getEndOffset() < MIN_RANGE_LENGTH) {
|
||||
addLast = false;
|
||||
Matcher matcher = toExclude.matcher(new StringUtil.BombedCharSequence(range.substring(text), 500));
|
||||
try {
|
||||
while (matcher.find()) {
|
||||
checkCancelled();
|
||||
TextRange found = matcherRange(range, matcher);
|
||||
till = found.getStartOffset();
|
||||
if (range.getEndOffset() - found.getEndOffset() < MIN_RANGE_LENGTH) {
|
||||
addLast = false;
|
||||
}
|
||||
if (!badSize(from, till)) {
|
||||
toCheck.add(new TextRange(from, till));
|
||||
}
|
||||
if (groupToInclude > 0) {
|
||||
TextRange contentFound = matcherRange(range, matcher, groupToInclude);
|
||||
if (badSize(contentFound.getEndOffset(), contentFound.getStartOffset())) {
|
||||
toCheck.add(TextRange.create(contentFound));
|
||||
}
|
||||
}
|
||||
from = found.getEndOffset();
|
||||
}
|
||||
if (!tooSmall(from, till)) {
|
||||
till = range.getEndOffset();
|
||||
if (badSize(from, till)) {
|
||||
return toCheck;
|
||||
}
|
||||
if (addLast) {
|
||||
toCheck.add(new TextRange(from, till));
|
||||
}
|
||||
if (groupToInclude > 0) {
|
||||
TextRange contentFound = matcherRange(range, matcher, groupToInclude);
|
||||
if (tooSmall(contentFound.getEndOffset(), contentFound.getStartOffset())) {
|
||||
toCheck.add(TextRange.create(contentFound));
|
||||
}
|
||||
}
|
||||
from = found.getEndOffset();
|
||||
}
|
||||
till = range.getEndOffset();
|
||||
if (tooSmall(from, till)) {
|
||||
return toCheck;
|
||||
}
|
||||
if (addLast) {
|
||||
toCheck.add(new TextRange(from, till));
|
||||
catch (ProcessCanceledException e) {
|
||||
//LOG.warn("Matching took too long: >>>" + range.substring(text) + "<<< " + toExclude);
|
||||
return Collections.singletonList(range);
|
||||
//return Collections.emptyList();
|
||||
}
|
||||
return toCheck;
|
||||
}
|
||||
|
||||
public static void checkCancelled() {
|
||||
|
||||
+39
-17
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PlainTextSplitter extends BaseSplitter {
|
||||
@@ -34,6 +35,10 @@ public class PlainTextSplitter extends BaseSplitter {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@NonNls
|
||||
private static final
|
||||
Pattern SPLIT_PATTERN = Pattern.compile("(\\s)");
|
||||
|
||||
@NonNls
|
||||
private static final Pattern MAIL =
|
||||
Pattern.compile("([\\p{L}0-9\\.\\-\\_]+@([\\p{L}0-9\\-\\_]+\\.)+(com|net|[a-z]{2}))");
|
||||
@@ -64,25 +69,42 @@ public class PlainTextSplitter extends BaseSplitter {
|
||||
// }
|
||||
//}
|
||||
|
||||
List<TextRange> toCheck;
|
||||
if (text.indexOf('@')>0) {
|
||||
toCheck = excludeByPattern(text, range, MAIL, 0);
|
||||
}
|
||||
else
|
||||
if (text.indexOf(':')>0) {
|
||||
toCheck = excludeByPattern(text, range, URL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
toCheck = Collections.singletonList(range);
|
||||
}
|
||||
|
||||
final TextSplitter ws = TextSplitter.getInstance();
|
||||
for (TextRange r : toCheck) {
|
||||
|
||||
int from = range.getStartOffset();
|
||||
int till;
|
||||
Matcher matcher = SPLIT_PATTERN.matcher(range.substring(text));
|
||||
while (true) {
|
||||
checkCancelled();
|
||||
|
||||
ws.split(text, r, consumer);
|
||||
List<TextRange> toCheck;
|
||||
TextRange wRange;
|
||||
String word;
|
||||
if(matcher.find()) {
|
||||
TextRange found = matcherRange(range, matcher);
|
||||
till = found.getStartOffset();
|
||||
if (badSize(from, till)) {
|
||||
continue;
|
||||
}
|
||||
wRange = new TextRange(from, till);
|
||||
word = wRange.substring(text);
|
||||
from = found.getEndOffset();
|
||||
} else { // end hit or zero matches
|
||||
wRange = new TextRange(from, range.getEndOffset());
|
||||
word = wRange.substring(text);
|
||||
}
|
||||
if (word.contains("@")) {
|
||||
toCheck = excludeByPattern(text, wRange, MAIL, 0);
|
||||
}
|
||||
else
|
||||
if (text.contains("://")) {
|
||||
toCheck = excludeByPattern(text, wRange, URL, 0);
|
||||
}
|
||||
else {
|
||||
toCheck = Collections.singletonList(wRange);
|
||||
}
|
||||
for (TextRange r : toCheck) {
|
||||
ws.split(text, r, consumer);
|
||||
}
|
||||
if(matcher.hitEnd()) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user