Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Kirill Kalishev
2011-04-13 17:54:51 +04:00
71 changed files with 1451 additions and 475 deletions
@@ -20,7 +20,10 @@ import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressManager;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
@@ -33,7 +36,6 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.javadoc.PsiDocTagValue;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -133,14 +135,14 @@ public class SuppressFix extends SuppressIntentionAction {
final PsiElement container,
final PsiModifierListOwner modifierOwner,
final String id) throws IncorrectOperationException {
PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierOwner, SuppressManagerImpl.SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierOwner, SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
final PsiAnnotation newAnnotation = createNewAnnotation(project, editor, container, annotation, id);
if (newAnnotation != null) {
if (annotation != null && annotation.isPhysical()) {
annotation.replace(newAnnotation);
} else {
final PsiNameValuePair[] attributes = newAnnotation.getParameterList().getAttributes();
new AddAnnotationFix(SuppressManagerImpl.SUPPRESS_INSPECTIONS_ANNOTATION_NAME, modifierOwner, attributes).invoke(project, editor, container.getContainingFile());
new AddAnnotationFix(SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME, modifierOwner, attributes).invoke(project, editor, container.getContainingFile());
}
}
}
@@ -156,8 +158,8 @@ public class SuppressFix extends SuppressIntentionAction {
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length == 1) {
final String suppressedWarnings = attributes[0].getText();
return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText("@" + SuppressManagerImpl
.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({" + suppressedWarnings + ", \"" + id + "\"})", container);
return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText("@" +
SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({" + suppressedWarnings + ", \"" + id + "\"})", container);
}
}
else {
@@ -174,7 +176,7 @@ public class SuppressFix extends SuppressIntentionAction {
}
else {
return JavaPsiFacade.getInstance(project).getElementFactory()
.createAnnotationFromText("@" + SuppressManagerImpl.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({\"" + id + "\"})", container);
.createAnnotationFromText("@" + SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({\"" + id + "\"})", container);
}
return null;
}
@@ -327,7 +327,7 @@ public class OverrideImplementUtil {
}
}
public static void annotate(PsiMethod result, String fqn, String... annosToRemove) throws IncorrectOperationException {
public static void annotate(@NotNull PsiMethod result, String fqn, String... annosToRemove) throws IncorrectOperationException {
Project project = result.getProject();
AddAnnotationFix fix = new AddAnnotationFix(fqn, result, annosToRemove);
if (fix.isAvailable(project, null, result.getContainingFile())) {
@@ -175,7 +175,7 @@ public class AddAnnotationFix extends PsiElementBaseIntentionAction implements L
}
}
PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation);
final @NotNull PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation);
if (myPairs != null) {
for (PsiNameValuePair pair : myPairs) {
inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue());
@@ -122,7 +122,9 @@ public class UnusedParametersInspection extends GlobalJavaInspectionTool {
final boolean[] found = {false};
for (int i = 0; i < derived.length && !found[0]; i++) {
if (!scope.contains(derived[i])) {
PsiParameter psiParameter = derived[i].getParameterList().getParameters()[idx];
final PsiParameter[] parameters = derived[i].getParameterList().getParameters();
if (parameters.length >= idx) continue;
PsiParameter psiParameter = parameters[idx];
ReferencesSearch.search(psiParameter, helper.getUseScope(psiParameter), false).forEach(new PsiReferenceProcessorAdapter(
new PsiReferenceProcessor() {
public boolean execute(PsiReference element) {
@@ -117,13 +117,16 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
for (int i = 0; i < overrides.length; i++) {
overrides[i] = (PsiMethod)overrides[i].getNavigationElement();
}
PsiElement[] elementsToSearch = new PsiElement[overrides.length + 1];
elementsToSearch[0] = parameter;
List<PsiElement> elementsToSearch = new ArrayList<PsiElement>(overrides.length + 1);
elementsToSearch.add(parameter);
int idx = method.getParameterList().getParameterIndex(parameter);
for (int i = 0; i < overrides.length; i++) {
elementsToSearch[i + 1] = overrides[i].getParameterList().getParameters()[idx];
for (PsiMethod override : overrides) {
final PsiParameter[] parameters = override.getParameterList().getParameters();
if (idx < parameters.length) {
elementsToSearch.add(parameters[idx]);
}
}
return elementsToSearch;
return elementsToSearch.toArray(new PsiElement[elementsToSearch.size()]);
}
@@ -304,11 +304,11 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
}
}
if(classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.PACKAGE)){
final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage("");
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, rootPackage);
if(rootPackage != null) rootPackage.processDeclarations(processor, state, null, place);
}
//if(classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.PACKAGE)){
// final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage("");
// processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, rootPackage);
// if(rootPackage != null) rootPackage.processDeclarations(processor, state, null, place);
//}
final PsiImportList importList = getImportList();
final PsiImportStaticStatement[] importStaticStatements = importList.getImportStaticStatements();
@@ -149,7 +149,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled()) {
new InplaceIntroduceConstantPopup(project, editor, parentClass, expr, localVariable, occurences, typeSelectorManager,
anchorElement, anchorElementIfAll,
createOccurenceManager(expr, parentClass)).performInplaceIntroduce();
expr != null ? createOccurenceManager(expr, parentClass) : null).performInplaceIntroduce();
return null;
}
@@ -108,7 +108,7 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler {
if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled()) {
myInplaceIntroduceFieldPopup =
new InplaceIntroduceFieldPopup(localVariable, parentClass, declareStatic, currentMethodConstructor, occurences, expr, typeSelectorManager, editor,
allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, createOccurenceManager(expr, parentClass));
allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, expr != null ? createOccurenceManager(expr, parentClass) : null);
myInplaceIntroduceFieldPopup.startTemplate();
return null;
}
@@ -15,6 +15,8 @@
*/
package com.intellij.slicer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Computable;
import com.intellij.usageView.UsageInfo;
import gnu.trove.THashMap;
import gnu.trove.TObjectHashingStrategy;
@@ -37,13 +39,17 @@ public class DuplicateMap {
};
private final Map<SliceUsage, SliceNode> myDuplicates = new THashMap<SliceUsage, SliceNode>(USAGEINFO_EQUALITY);
public SliceNode putNodeCheckDupe(SliceNode node) {
SliceUsage usage = node.getValue();
SliceNode eq = myDuplicates.get(usage);
if (eq == null) {
myDuplicates.put(usage, node);
}
return eq;
public SliceNode putNodeCheckDupe(final SliceNode node) {
return ApplicationManager.getApplication().runReadAction(new Computable<SliceNode>() {
public SliceNode compute() {
SliceUsage usage = node.getValue();
SliceNode eq = myDuplicates.get(usage);
if (eq == null) {
myDuplicates.put(usage, node);
}
return eq;
}
});
}
public void clear() {
@@ -0,0 +1,5 @@
package x;
class InvalidUse {
<error descr="Cannot resolve symbol 'Test'">Test</error> t = null;
}
@@ -79,6 +79,7 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase {
public void testAlreadyImportedClass() throws Exception { doTest(BASE_PATH+"/alreadyImportedClass/pack/AlreadyImportedClass.java", BASE_PATH+"/alreadyImportedClass", false, false); }
public void testImportDefaultPackage() throws Exception { doTest(BASE_PATH+"/importDefaultPackage/x/Usage.java", BASE_PATH+"/importDefaultPackage", false, false); }
public void testImportDefaultPackage2() throws Exception { doTest(BASE_PATH+"/importDefaultPackage/x/ImportOnDemandUsage.java", BASE_PATH+"/importDefaultPackage", false, false); }
public void testImportDefaultPackageInvalid() throws Exception { doTest(BASE_PATH+"/importDefaultPackage/x/InvalidUse.java", BASE_PATH+"/importDefaultPackage", false, false); }
public void testScopeBased() throws Exception {
NamedScope xScope = new NamedScope("xxx", new PatternPackageSet("x..*", PatternPackageSet.SCOPE_SOURCE, null));
@@ -46,7 +46,7 @@ public abstract class PsiElementBaseIntentionAction extends BaseIntentionAction
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
final PsiElement element = getElement(editor, file);
return element == null ? false : isAvailable(project, editor, element);
return element != null && isAvailable(project, editor, element);
}
@Nullable
@@ -288,7 +288,7 @@ class DaemonListeners implements Disposable {
LOG.assertTrue(((UserDataHolderEx)myProject).replace(DAEMON_INITIALIZED, Boolean.TRUE, null), "Daemon listeners already disposed for the project "+myProject);
}
boolean canChangeFileSilently(PsiFileSystemItem file) {
boolean canChangeFileSilently(@NotNull PsiFileSystemItem file) {
if (cutOperationJustHappened) return false;
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) return false;
@@ -302,7 +302,7 @@ class DaemonListeners implements Disposable {
return canUndo(virtualFile);
}
private boolean canUndo(VirtualFile virtualFile) {
private boolean canUndo(@NotNull VirtualFile virtualFile) {
for (FileEditor editor : FileEditorManager.getInstance(myProject).getEditors(virtualFile)) {
if (UndoManager.getInstance(myProject).isUndoAvailable(editor)) return true;
}
@@ -312,13 +312,14 @@ class DaemonListeners implements Disposable {
private static enum Result {
CHANGED, UNCHANGED, NOT_SURE
}
private Result vcsThinksItChanged(VirtualFile virtualFile, Project project) {
AbstractVcs activeVcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(virtualFile);
if (activeVcs == null) return Result.NOT_SURE;
FilePath path = new FilePathImpl(virtualFile);
boolean vcsIsThinking = !VcsDirtyScopeManager.getInstance(myProject).whatFilesDirty(Arrays.asList(path)).isEmpty();
if (vcsIsThinking) return Result.UNCHANGED; // do not modify file which is in the process of updating
if (vcsIsThinking) return Result.NOT_SURE; // do not modify file which is in the process of updating
FileStatus status = FileStatusManager.getInstance(project).getStatus(virtualFile);
if (status == FileStatus.UNKNOWN) return Result.NOT_SURE;
@@ -150,13 +150,22 @@ public class FileStatusMap implements Disposable {
}
public void markAllFilesDirty() {
assert myAllowDirt;
assertAllowModifications();
LOG.debug("********************************* Mark all dirty");
synchronized (myDocumentToStatusMap) {
myDocumentToStatusMap.clear();
}
}
private void assertAllowModifications() {
try {
assert myAllowDirt;
}
finally {
myAllowDirt = true; //give next test a chance
}
}
public void markFileUpToDate(@NotNull Document document, @NotNull PsiFile file, int passId) {
synchronized(myDocumentToStatusMap){
FileStatus status = myDocumentToStatusMap.get(document);
@@ -204,7 +213,7 @@ public class FileStatusMap implements Disposable {
}
public void markFileScopeDirty(@NotNull Document document, int passId) {
assert myAllowDirt;
assertAllowModifications();
synchronized(myDocumentToStatusMap){
FileStatus status = myDocumentToStatusMap.get(document);
if (status == null){
@@ -226,7 +235,7 @@ public class FileStatusMap implements Disposable {
}
public void markFileScopeDirtyDefensively(@NotNull PsiFile file) {
assert myAllowDirt;
assertAllowModifications();
if (LOG.isDebugEnabled()) {
LOG.debug("********************************* Mark dirty file defensively: "+file.getName());
}
@@ -242,7 +251,7 @@ public class FileStatusMap implements Disposable {
}
public void markFileScopeDirty(@NotNull Document document, @NotNull TextRange scope, int fileLength) {
assert myAllowDirt;
assertAllowModifications();
if (LOG.isDebugEnabled()) {
LOG.debug("********************************* Mark dirty: "+scope);
}
@@ -287,19 +287,28 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
@Override
public Collection<RunnerAndConfigurationSettings> getSortedConfigurations() {
if (!myOrdered && !myOrder.isEmpty()) { //compatibility
if (!myOrdered) { //compatibility
final HashMap<String, RunnerAndConfigurationSettings> settings =
new HashMap<String, RunnerAndConfigurationSettings>(myConfigurations); //sort shared and local configurations
new HashMap<String, RunnerAndConfigurationSettings>(myConfigurations); //sort shared and local configurations
myConfigurations.clear();
final List<String> order = new ArrayList<String>(settings.keySet());
Collections.sort(order, new Comparator<String>() {
public int compare(final String o1, final String o2) {
return myOrder.indexOf(o1) - myOrder.indexOf(o2);
}
});
for (String configName : order) {
if (myOrder.isEmpty()) {
// IDEA-63663 Sort run configurations alphabetically if clean checkout
Collections.sort(order);
}
else {
Collections.sort(order, new Comparator<String>() {
public int compare(final String o1, final String o2) {
return myOrder.indexOf(o1) - myOrder.indexOf(o2);
}
});
}
for (final String configName : order) {
myConfigurations.put(configName, settings.get(configName));
}
myOrdered = true;
}
return myConfigurations.values();
@@ -65,6 +65,11 @@ public class RangeMarkerWindow implements RangeMarkerEx {
myHostMarker.trackInvalidation(track);
}
@Override
public boolean isTrackInvalidation() {
return myHostMarker.isTrackInvalidation();
}
////////////////////////////delegates
public void setGreedyToLeft(final boolean greedy) {
myHostMarker.setGreedyToLeft(greedy);
@@ -33,6 +33,7 @@ import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
@@ -630,8 +631,13 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
if (commitNecessary && ApplicationManager.getApplication().getCurrentWriteAction(ExternalChangeAction.class) != null){
commitDocument(document);
}
// avoid documents piling up during batch processing
if (FileDocumentManagerImpl.areTooManyDocumentsInTheQueue(myUncommittedDocuments)) {
commitAllDocuments();
}
}
private boolean isRelevant(FileViewProvider viewProvider) {
VirtualFile virtualFile = viewProvider.getVirtualFile();
return !virtualFile.getFileType().isBinary() && viewProvider.getManager() == myPsiManager && !myPsiManager.getProject().isDisposed();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -103,10 +103,13 @@ public abstract class ActionPlaces {
public static final String TFS_TREE_POPUP = "TfsTreePopup";
public static final String ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION = "ActionPlace.VcsQuickListPopupAction";
public static final String PHING_EXPLORER_POPUP = "PhingExplorerPopup";
public static final String PHING_EXPLORER_TOOLBAR = "PhingExplorerToolbar";
private static final String[] ourToolbarPlaces = new String[]{EDITOR_TOOLBAR, PROJECT_VIEW_TOOLBAR, TESTTREE_VIEW_TOOLBAR, MAIN_TOOLBAR,
ANT_EXPLORER_TOOLBAR, ANT_MESSAGES_TOOLBAR, COMPILER_MESSAGES_TOOLBAR, TODO_VIEW_TOOLBAR, STRUCTURE_VIEW_TOOLBAR, USAGE_VIEW_TOOLBAR,
DEBUGGER_TOOLBAR, CALL_HIERARCHY_VIEW_TOOLBAR, METHOD_HIERARCHY_VIEW_TOOLBAR, TYPE_HIERARCHY_VIEW_TOOLBAR, JAVADOC_TOOLBAR,
FILE_HISTORY_TOOLBAR, FILEHISTORY_VIEW_TOOLBAR, LVCS_DIRECTORY_HISTORY_TOOLBAR, CHANGES_VIEW_TOOLBAR, };
FILE_HISTORY_TOOLBAR, FILEHISTORY_VIEW_TOOLBAR, LVCS_DIRECTORY_HISTORY_TOOLBAR, CHANGES_VIEW_TOOLBAR, PHING_EXPLORER_TOOLBAR };
public static boolean isToolbarPlace(@NotNull String place) {
return ArrayUtil.find(ourToolbarPlaces, place) != -1;
@@ -118,7 +121,7 @@ public abstract class ActionPlaces {
STRUCTURE_VIEW_POPUP, TODO_VIEW_POPUP, COMPILER_MESSAGES_POPUP, ANT_MESSAGES_POPUP, ANT_EXPLORER_POPUP, UPDATE_POPUP,
FILEVIEW_POPUP, CHECKOUT_POPUP, LVCS_DIRECTORY_HISTORY_POPUP, GUI_DESIGNER_EDITOR_POPUP, GUI_DESIGNER_COMPONENT_TREE_POPUP, GUI_DESIGNER_PROPERTY_INSPECTOR_POPUP,
CREATE_EJB_POPUP, CHANGES_VIEW_POPUP, REMOTE_HOST_VIEW_POPUP, REMOTE_HOST_DIALOG_POPUP, TFS_TREE_POPUP,
ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION
ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION , PHING_EXPLORER_POPUP
};
public static boolean isPopupPlace(@NotNull String place) {
@@ -0,0 +1,107 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.buildfiles;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.FileAttribute;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Created by IntelliJ IDEA.
* User: lene
* Date: 04.04.11
* Time: 17:40
*/
public class ForcedBuildFileAttribute {
private static final Logger LOG = Logger.getInstance("#" + ForcedBuildFileAttribute.class.getName());
private static final FileAttribute FRAMEWORK_FILE_ATTRIBUTE = new FileAttribute("forcedBuildFileFrameworkAttribute", 1, false);
private static final Key<String> FRAMEWORK_FILE_MARKER = Key.create("forcedBuildFileFrameworkAttribute");
private ForcedBuildFileAttribute() {
}
public static boolean belongsToFramework(VirtualFile file, @NotNull String frameworkId) {
return frameworkId.equals(getFrameworkIdOfBuildFile(file));
}
@Nullable
public static String getFrameworkIdOfBuildFile(VirtualFile file) {
if (file instanceof NewVirtualFile) {
final DataInputStream is = FRAMEWORK_FILE_ATTRIBUTE.readAttribute(file);
if (is != null) {
try {
try {
/*
//todo[lene] IOUtil throws java.io.EOFException
at java.io.DataInputStream.readFully(DataInputStream.java:180)
at java.io.DataInputStream.readFully(DataInputStream.java:152)
at com.intellij.util.io.IOUtil.readString(IOUtil.java:40)
at com.intellij.buildfiles.ForcedBuildFileAttribute.getFrameworkIdOfBuildFile(ForcedBuildFileAttribute.java:59)
*/
return is.readUTF();
}
finally {
is.close();
}
}
catch (IOException e) {
LOG.error(e);
}
}
return "";
}
return file.getUserData(FRAMEWORK_FILE_MARKER);
}
public static void forceFileToFramework(VirtualFile file, String frameworkId, boolean value) {
if (!value && !frameworkId.equals(getFrameworkIdOfBuildFile(file))) {//belongs to other framework
return;
}
forceBuildFile(file, frameworkId);
}
private static void forceBuildFile(VirtualFile file, String value) {
if (file instanceof NewVirtualFile) {
final DataOutputStream os = FRAMEWORK_FILE_ATTRIBUTE.writeAttribute(file);
try {
try {
os.writeUTF(value);
}
finally {
os.close();
}
}
catch (IOException e) {
LOG.error(e);
}
}
else {
file.putUserData(FRAMEWORK_FILE_MARKER, value);
}
}
}
@@ -40,6 +40,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.DocumentEvent;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;
@@ -80,8 +81,14 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar {
ContainerUtil.addAll(myStopWords, stopWords);
//index
final URL indexResource = ResourceUtil.getResource(SearchableOptionsRegistrar.class, "/search/", "searchableOptions.xml");
if (indexResource == null) {
LOG.info("No /search/searchableOptions.xml found, settings search won't work!");
return;
}
Document document =
JDOMUtil.loadDocument(ResourceUtil.getResource(SearchableOptionsRegistrar.class, "/search/", "searchableOptions.xml"));
JDOMUtil.loadDocument(indexResource);
Element root = document.getRootElement();
List configurables = root.getChildren("configurable");
for (final Object o : configurables) {
@@ -33,9 +33,11 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
class UndoableGroup {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.command.impl.UndoableGroup");
@@ -115,71 +117,56 @@ class UndoableGroup {
}
}
private static void doInBulkMode(@NotNull final Runnable action, @NotNull Collection<DocumentEx> documents) {
Runnable runnable = action;
for (final DocumentEx document : documents) {
final Runnable oldRunnable = runnable;
runnable = new Runnable() {
@Override
public void run() {
doInBulkMode(oldRunnable, document);
}
};
}
runnable.run();
}
private static void doInBulkMode(@NotNull Runnable action, @NotNull DocumentEx document) {
boolean wasInBulkUpdate = document.isInBulkUpdate();
document.setInBulkUpdate(true);
try {
action.run();
}
finally {
if (!wasInBulkUpdate) {
document.setInBulkUpdate(false);
}
}
}
private void doUndoOrRedo(final boolean isUndo) {
Runnable runnable = new Runnable() {
final boolean wrapInBulkUpdate = myActions.size() > 50;
// perform undo action by action, setting bulk update flag if possible
// if multiple consecutive actions share a document, then set the bulk flag only once
final Set<DocumentEx> bulkDocuments = new THashSet<DocumentEx>();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
try {
for (UndoableAction each : isUndo ? ContainerUtil.iterateBackward(myActions) : myActions) {
if (isUndo) {
each.undo();
for (final UndoableAction action : isUndo ? ContainerUtil.iterateBackward(myActions) : myActions) {
final Collection<DocumentEx> newDocuments;
if (wrapInBulkUpdate) {
newDocuments = new THashSet<DocumentEx>();
Set<DocumentEx> documentsToRemoveFromBulk = new THashSet<DocumentEx>(bulkDocuments);
DocumentReference[] affectedDocuments = action.getAffectedDocuments();
if (affectedDocuments != null) {
for (DocumentReference affectedDocument : affectedDocuments) {
DocumentEx document = (DocumentEx)affectedDocument.getDocument();
if (document == null) continue;
documentsToRemoveFromBulk.remove(document);
if (bulkDocuments.contains(document)) continue;
newDocuments.add(document);
document.setInBulkUpdate(true);
}
}
for (DocumentEx document : documentsToRemoveFromBulk) {
document.setInBulkUpdate(false);
}
bulkDocuments.removeAll(documentsToRemoveFromBulk);
bulkDocuments.addAll(newDocuments);
}
else {
each.redo();
newDocuments = Collections.emptyList();
}
if (isUndo) {
action.undo();
}
else {
action.redo();
}
}
for (DocumentEx bulkDocument : bulkDocuments) {
bulkDocument.setInBulkUpdate(false);
}
}
catch (UnexpectedUndoException e) {
reportUndoProblem(e, isUndo);
}
}
};
if (myActions.size() > 50) {
final Collection<DocumentEx> documents = new THashSet<DocumentEx>();
for (UndoableAction action : myActions) {
DocumentReference[] affectedDocuments = action.getAffectedDocuments();
if (affectedDocuments != null) {
for (DocumentReference affectedDocument : affectedDocuments) {
documents.add((DocumentEx)affectedDocument.getDocument());
}
}
}
final Runnable oldRunnable = runnable;
runnable = new Runnable() {
@Override
public void run() {
doInBulkMode(oldRunnable, documents);
}
};
}
ApplicationManager.getApplication().runWriteAction(runnable);
});
commitAllDocuments();
}
@@ -35,5 +35,5 @@ public interface RangeMarkerEx extends RangeMarker, MutableInterval, Segment {
long getId();
void trackInvalidation(boolean track);
boolean isTrackInvalidation();
}
@@ -187,11 +187,18 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
private void getNearestHighlighters(MarkupModelEx markupModel, MouseEvent e, final double width, final Collection<RangeHighlighter> nearest) {
if (0 > e.getX() || e.getX() >= width) return;
int startOffset = yPositionToOffset(e.getY()-getMinHeight(), true);
int endOffset = yPositionToOffset(e.getY()+getMinHeight(), false);
final int y = e.getY();
int startOffset = yPositionToOffset(y -getMinHeight(), true);
int endOffset = yPositionToOffset(y +getMinHeight(), false);
markupModel.processHighlightsOverlappingWith(startOffset, endOffset, new Processor<RangeHighlighterEx>() {
public boolean process(RangeHighlighterEx highlighter) {
if (highlighter.getErrorStripeMarkColor() != null) nearest.add(highlighter);
if (highlighter.getErrorStripeMarkColor() != null) {
ProperTextRange range = offsetToYPosition(highlighter.getStartOffset(), highlighter.getEndOffset());
if (range.getStartOffset() >= y - getMinHeight() * 2 &&
range.getEndOffset() <= y + getMinHeight() * 2) {
nearest.add(highlighter);
}
}
return true;
}
});
@@ -797,6 +804,16 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
if (line < 0) return 0;
if (line >= document.getLineCount()) return document.getTextLength();
return beginLine ? document.getLineStartOffset(line) : document.getLineEndOffset(line);
final FoldingModelEx foldingModel = myEditor.getFoldingModel();
if (beginLine) {
final int offset = document.getLineStartOffset(line);
final FoldRegion startCollapsed = foldingModel.getCollapsedRegionAtOffset(offset);
return startCollapsed != null ? Math.min(offset, startCollapsed.getStartOffset()) : offset;
}
else {
final int offset = document.getLineEndOffset(line);
final FoldRegion startCollapsed = foldingModel.getCollapsedRegionAtOffset(offset);
return startCollapsed != null ? Math.max(offset, startCollapsed.getEndOffset()) : offset;
}
}
}
@@ -45,7 +45,7 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
private final ReferenceQueue<T> myReferenceQueue = new ReferenceQueue<T>();
private int deadReferenceCount;
protected class IntervalNode extends Node<T> implements MutableInterval/*, Iterable<T>, Iterator<T>*/ {
protected class IntervalNode extends Node<T> implements MutableInterval {
private volatile int myStart;
private volatile int myEnd;
private volatile boolean isValid = true;
@@ -181,11 +181,11 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
return myEnd;
}
public IntervalTreeImpl getTree() {
public IntervalTreeImpl<T> getTree() {
return IntervalTreeImpl.this;
}
}
private void pushDeltaFromRoot(IntervalNode node) {
if (normalized) return;
if (node != null) {
@@ -437,7 +437,7 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
}
}
public IntervalNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) {
public IntervalTreeImpl<T>.IntervalNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) {
try {
l.writeLock().lock();
checkMax(true);
@@ -502,7 +502,7 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
int maxRightStart = r.second;
if (!root.isValid()) {
allValid.set(false);
if (assertInvalid) assert false : (T)root;
if (assertInvalid) assert false : root;
return Trinity.create(Math.min(minLeftStart, minRightStart), Math.max(maxLeftStart, maxRightStart), Math.max(maxRightEnd, maxLeftEnd));
}
IntervalNode parent = root.getParent();
@@ -45,7 +45,7 @@ class PersistentRangeHighlighterImpl extends RangeHighlighterImpl implements Ran
if (PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this)) {
setLine(event.translateLineViaDiff(getLine()));
if (getLine() < 0 || getLine() >= getDocument().getLineCount()) {
invalidate();
invalidate(e);
}
else {
DocumentEx document = getDocument();
@@ -36,23 +36,23 @@ class PersistentRangeMarker extends RangeMarkerImpl {
PersistentRangeMarker(DocumentEx document, int startOffset, int endOffset, boolean register) {
super(document, startOffset, endOffset, register);
storeLinesAndCols();
storeLinesAndCols(null);
}
private void storeLinesAndCols() {
private void storeLinesAndCols(DocumentEvent e) {
// document might have been changed already
if (getStartOffset() < myDocument.getTextLength()) {
myStartLine = myDocument.getLineNumber(getStartOffset());
myStartColumn = getStartOffset() - myDocument.getLineStartOffset(myStartLine);
if (myStartColumn < 0) {
invalidate();
invalidate(e);
}
}
if (getEndOffset() < myDocument.getTextLength()) {
myEndLine = myDocument.getLineNumber(getEndOffset());
myEndColumn = getEndOffset() - myDocument.getLineStartOffset(myEndLine);
if (myEndColumn < 0) {
invalidate();
invalidate(e);
}
}
}
@@ -63,7 +63,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
if (PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this)){
myStartLine = event.translateLineViaDiffStrict(myStartLine);
if (myStartLine < 0 || myStartLine >= getDocument().getLineCount()){
invalidate();
invalidate(e);
}
else{
setIntervalStart(getDocument().getLineStartOffset(myStartLine) + myStartColumn);
@@ -71,7 +71,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
myEndLine = event.translateLineViaDiffStrict(myEndLine);
if (myEndLine < 0 || myEndLine >= getDocument().getLineCount()){
invalidate();
invalidate(e);
}
else{
setIntervalEnd(getDocument().getLineStartOffset(myEndLine) + myEndColumn);
@@ -80,11 +80,11 @@ class PersistentRangeMarker extends RangeMarkerImpl {
else {
super.changedUpdateImpl(e);
if (isValid()){
storeLinesAndCols();
storeLinesAndCols(e);
}
}
if (getEndOffset() < getStartOffset() || getEndOffset() > getDocument().getTextLength()) {
invalidate();
invalidate(e);
}
}
@@ -19,7 +19,9 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.RangeMarkerEx;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -30,7 +32,6 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
protected final DocumentEx myDocument;
RangeMarkerTree.RMNode myNode;
private boolean myTrackInvalidation;
private final long myId;
//private static long counter;
@@ -91,8 +92,21 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
return intervalEnd() + (node == null ? 0 : node.computeDeltaUpToRoot());
}
public void invalidate() {
public void invalidate(final DocumentEvent e) {
setValid(false);
RangeMarkerTree<RangeMarkerEx>.RMNode node = myNode;
if (node != null) {
node.processAliveKeys(new Processor<RangeMarkerEx>() {
@Override
public boolean process(RangeMarkerEx markerEx) {
if (markerEx.isTrackInvalidation()) {
LOG.error("Range marker invalidated: "+markerEx +"; say thanks to the "+e);
}
return true;
}
});
}
}
@NotNull
@@ -133,7 +147,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
if (intervalStart() > intervalEnd() || intervalStart() < 0 || intervalEnd() > docLength - e.getNewLength() + e.getOldLength()) {
LOG.error("RangeMarker" + (isGreedyToLeft() ? "[" : "(") + oldStart + ", " + oldEnd + (isGreedyToRight() ? "]" : ")") +
" is invalid before update. Event = " + e + ". Doc length=" + docLength + "; "+getClass());
invalidate();
invalidate(e);
return;
}
changedUpdateImpl(e);
@@ -143,7 +157,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
"old doc length=" + docLength + "; real doc length = "+myDocument.getTextLength()+
"; "+getClass()+"." +
" Before update: '"+markerBefore+"'; After update: '"+this+"'");
invalidate();
invalidate(e);
}
}
@@ -192,7 +206,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
return;
}
invalidate();
invalidate(e);
}
private void processIfOnePoint(DocumentEvent e) {
@@ -200,7 +214,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
int oldLength = e.getOldLength();
int oldEnd = offset + oldLength;
if (offset < intervalStart() && intervalStart() < oldEnd) {
invalidate();
invalidate(e);
return;
}
@@ -237,17 +251,17 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
return node != null && node.isValid();
}
private static final Key<Boolean> TRACK_INVALIDATION_KEY = new Key<Boolean>("TRACK_INVALIDATION_KEY");
@Override
public void trackInvalidation(boolean track) {
myTrackInvalidation = track;
putUserData(TRACK_INVALIDATION_KEY, track ? Boolean.TRUE : null);
}
public boolean isTrackInvalidation() {
return getUserData(TRACK_INVALIDATION_KEY) == Boolean.TRUE;
}
@Override
public boolean setValid(boolean value) {
if (!value && myTrackInvalidation) {
LOG.error("Range marker invalidated");
}
RangeMarkerTree.RMNode node = myNode;
return node == null || node.setValid(value);
}
@@ -82,10 +82,10 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
}
@Override
public IntervalNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) {
public RangeMarkerTree<T>.RMNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) {
RangeMarkerImpl marker = (RangeMarkerImpl)interval;
marker.setValid(true);
RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer);
RangeMarkerTree<T>.RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer);
((RangeMarkerImpl)interval).myNode = node;
checkBelongsToTheTree(interval, true);
@@ -106,8 +106,8 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
}
@Override
protected IntervalNode lookupNode(@NotNull T key) {
return ((RangeMarkerImpl)key).myNode;
protected RangeMarkerTree<T>.RMNode lookupNode(@NotNull T key) {
return (RMNode)((RangeMarkerImpl)key).myNode;
}
public class RMNode extends IntervalNode {
@@ -131,7 +131,7 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
@Override
public void addInterval(@NotNull T interval) {
super.addInterval(interval);
((RangeMarkerImpl)interval).myNode = this;
((RangeMarkerImpl)interval).myNode = (RangeMarkerTree.RMNode)this;
checkBelongsToTheTree(interval, true);
}
@@ -44,6 +44,7 @@ import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.ex.dummy.DummyFileSystem;
@@ -135,6 +136,11 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
Project project = currentCommand == null ? null : CommandProcessor.getInstance().getCurrentCommandProject();
String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
document.putUserData(LINE_SEPARATOR_KEY, lineSeparator);
// avoid documents piling up during batch processing
if (areTooManyDocumentsInTheQueue(myUnsavedDocuments)) {
saveAllDocuments();
}
}
}
);
@@ -148,6 +154,16 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
return document;
}
public static boolean areTooManyDocumentsInTheQueue(Collection<Document> documents) {
if (documents.size() > 100) return true;
int totalSize = 0;
for (Document document : documents) {
totalSize += document.getTextLength();
if (totalSize > 10 * FileUtil.MEGABYTE) return true;
}
return false;
}
private static Document createDocument(final CharSequence text) {
return EditorFactory.getInstance().createDocument(text);
}
@@ -110,7 +110,7 @@ public class UsagePreviewPanel extends JPanel implements Disposable {
TextRange elementRange = psiElement.getTextRange();
TextRange infoRange = info.getRangeInElement();
TextRange textRange = elementRange.intersection(infoRange);
TextRange textRange = infoRange == null ? null : elementRange.intersection(infoRange);
if (textRange == null) textRange = elementRange;
// hack to determine element range to highlight
if (psiElement instanceof PsiNamedElement && !(psiElement instanceof PsiFile)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -120,7 +120,7 @@ public class FileUtil {
* @param strict if {@code false} then this method returns {@code true} if {@code ancestor}
* and {@code file} are equal
* @return {@code true} if {@code ancestor} is parent of {@code file}; {@code false} otherwise
* @throws IOException this exception is never thrown and left here for backward compatibilty
* @throws IOException this exception is never thrown and left here for backward compatibilty
*/
public static boolean isAncestor(@NotNull File ancestor, @NotNull File file, boolean strict) throws IOException {
File parent = strict ? getParentFile(file) : file;
@@ -902,7 +902,7 @@ public class FileUtil {
/**
* Has duplicate: {@link com.intellij.coverage.listeners.CoverageListener#sanitize(java.lang.String, java.lang.String)}
* as FileUtil is not available in client's vm
* as FileUtil is not available in client's vm
*/
@NotNull
public static String sanitizeFileName(@NotNull String name) {
@@ -1016,4 +1016,51 @@ public class FileUtil {
}
return found;
}
/**
* Returns empty string for empty path.
* First checks whether provided path is a path of a file with sought-for name.
* Unless found, checks if provided file was a directory. In this case checks existance
* of child files with given names in order "as provided". Finally checks filename among
* brother-files of provided. Returns null if nothing found.
*
* @return path of the first of found files or empty string or null.
*/
@Nullable
public static String findFileInProvidedPath(String providedPath, String... fileNames) {
if (StringUtil.isEmpty(providedPath)) {
return "";
}
File providedFile = new File(providedPath);
if (providedFile.exists()) {
String name = providedFile.getName();
for (String fileName : fileNames) {
if (name.equals(fileName)) {
return toSystemDependentName(providedFile.getPath());
}
}
}
if (providedFile.isDirectory()) { //user chose folder with file
for (String fileName : fileNames) {
File file = new File(providedFile, fileName);
if (fileName.equals(file.getName()) && file.exists()) {
return toSystemDependentName(file.getPath());
}
}
}
providedFile = providedFile.getParentFile(); //users chose wrong file in same directory
if (providedFile != null && providedFile.exists()) {
for (String fileName : fileNames) {
File file = new File(providedFile, fileName);
if (fileName.equals(file.getName()) && file.exists()) {
return toSystemDependentName(file.getPath());
}
}
}
return null;
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.util.io;
import com.intellij.openapi.util.text.StringUtil;
import junit.framework.TestCase;
import java.io.File;
import java.io.IOException;
/**
* Created by IntelliJ IDEA.
* User: lene
* Date: 29.03.11
* Time: 17:16
*/
public class FileUtilFindFileTest extends TestCase {
private final File myTempFile;
private final File myFirstFile;
private final File mySecondFile;
@SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
public FileUtilFindFileTest() throws IOException {
myTempFile = FileUtil.createTempDirectory("tEF", ""); //NON-NLS
myFirstFile = new File(myTempFile, "first");
mySecondFile = new File(myTempFile, "second"); //NON-NLS
assertTrue(myFirstFile.createNewFile());
assertTrue(mySecondFile.createNewFile());
}
public void testNonExistingFileInNonExistentDirectory() throws Exception {
String path = FileUtil.findFileInProvidedPath("123", "zero");//NON-NLS
assertTrue(StringUtil.isEmpty(path));
}
public void testNonExistingFileInDirectory() throws Exception {
String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "zero");//NON-NLS
assertTrue(StringUtil.isEmpty(path));
}
public void testNonExistingFile() throws Exception {
String path =
FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath() + "123", myFirstFile.getName() + "123");
assertTrue(StringUtil.isEmpty(path));
}
public void testExistingFileInDirectory() throws Exception {
String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "first");
assertEquals(path, myFirstFile.getAbsolutePath());
}
public void testExistingFile() throws Exception {
String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "first");
assertEquals(path, myFirstFile.getAbsolutePath());
}
public void testTwoFilesOrderInDirectory() throws Exception {
String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "first", "second"); //NON-NLS
assertEquals(path, myFirstFile.getAbsolutePath());
}
public void testTwoFilesOrderInDirectory2() throws Exception {
String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "second", "first"); //NON-NLS
assertEquals(path, mySecondFile.getAbsolutePath());
}
public void testTwoFilesOrder() throws Exception {
String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "first", "second");//NON-NLS
assertEquals(path, myFirstFile.getAbsolutePath());
}
public void testTwoFilesOrder2() throws Exception {
String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "second", "first"); //NON-NLS
assertEquals(path, myFirstFile.getAbsolutePath());
}
}
@@ -51,6 +51,7 @@ import com.intellij.util.continuation.*;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.Topic;
import com.intellij.util.text.CharArrayCharSequence;
import com.intellij.vcsUtil.FilesProgress;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -237,9 +238,9 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
public List<ShelvedChangeList> importChangeLists(final Collection<VirtualFile> files, final Consumer<VcsException> exceptionConsumer) {
final List<ShelvedChangeList> result = new ArrayList<ShelvedChangeList>(files.size());
try {
final FilesProgress filesProgress = new FilesProgress(files.size(), "Processing ");
for (VirtualFile file : files) {
ProgressManager.checkCanceled();
filesProgress.updateIndicator(file);
final String description = file.getNameWithoutExtension().replace('_', ' ');
final File patchPath = getPatchPath(description);
final ShelvedChangeList list = new ShelvedChangeList(patchPath.getPath(), description, new SmartList<ShelvedBinaryFile>(),
@@ -28,7 +28,7 @@ import java.util.*;
public abstract class GenericNotifierImpl<T, Key> {
private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.GenericNotifier");
private final Project myProject;
protected final Project myProject;
@NotNull
private final String myGroupId; //+- here
@NotNull
@@ -181,4 +181,10 @@ public abstract class GenericNotifierImpl<T, Key> {
private static void log(final String s) {
LOG.debug(s);
}
public boolean isEmpty() {
synchronized (myLock) {
return myState.isEmpty();
}
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.vcsUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.vfs.VirtualFile;
/**
* @author irengrig
* Date: 4/8/11
* Time: 5:15 PM
*/
public class FilesProgress {
private final double myTotal;
private final String myPrefix;
private final ProgressIndicator myProgressIndicator;
private int myCnt;
private boolean myInText2;
public FilesProgress(double total, final String prefix) {
myTotal = total;
myPrefix = prefix;
myProgressIndicator = ProgressManager.getInstance().getProgressIndicator();
myCnt = 0;
myInText2 = false;
}
public void updateIndicator(final VirtualFile vf) {
if (myProgressIndicator == null) return;
myProgressIndicator.checkCanceled();
if (myInText2) {
myProgressIndicator.setText2(myPrefix + getFileDescriptionForProgress(vf));
} else {
myProgressIndicator.setText(myPrefix + getFileDescriptionForProgress(vf));
}
myProgressIndicator.setFraction(myCnt/myTotal);
++ myCnt;
}
private static String getFileDescriptionForProgress(final VirtualFile file) {
final VirtualFile parent = file.getParent();
return file.getName() + " (" + (parent == null ? file.getPath() : parent.getPath()) + ")";
}
public void setInText2(boolean inText2) {
myInText2 = inText2;
}
}
@@ -1878,3 +1878,6 @@ arrays.hash.code.quickfix=Replace with 'Arrays.hashCode()'
method.can.be.variable.arity.method.display.name=Method can be variable arity method
method.can.be.variable.arity.method.problem.descriptor=<code>#ref()</code> can be converted to variable arity method
convert.to.variable.arity.method.quickfix=Convert to variable arity method
mismatched.string.builder.query.update.display.name=Mismatched query and update of StringBuilder
mismatched.string.builder.updated.problem.descriptor=Contents of {0} <code>#ref</code> are updated, but never queried #loc
mismatched.string.builder.queried.problem.descriptor=Contents of {0} <code>#ref</code> are queried, but never updated #loc
@@ -552,6 +552,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent,
}
m_inspectionClasses.add(MismatchedArrayReadWriteInspection.class);
m_inspectionClasses.add(MismatchedCollectionQueryUpdateInspection.class);
m_inspectionClasses.add(MismatchedStringBuilderQueryUpdateInspection.class);
m_inspectionClasses.add(MisspelledCompareToInspection.class);
m_inspectionClasses.add(MisspelledHashcodeInspection.class);
m_inspectionClasses.add(MisspelledEqualsInspection.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ import com.intellij.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
class CollectionQueryCalledVisitor extends JavaRecursiveElementVisitor{
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2011 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2011 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,7 +18,6 @@ package com.siyeh.ig.bugs;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.HardcodedMethodConstants;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -78,11 +77,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{
return;
}
final PsiClass containingClass = PsiUtil.getTopLevelClass(field);
if(containingClass == null){
return;
}
final PsiType type = field.getType();
if(type.getArrayDimensions() == 0){
if(!checkVariable(field, containingClass)){
return;
}
final boolean written =
@@ -99,11 +94,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{
super.visitLocalVariable(variable);
final PsiCodeBlock codeBlock =
PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
if(codeBlock == null){
return;
}
final PsiType type = variable.getType();
if(type.getArrayDimensions() == 0){
if(!checkVariable(variable, codeBlock)){
return;
}
final boolean written =
@@ -115,6 +106,28 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{
registerVariableError(variable, Boolean.valueOf(written));
}
private static boolean checkVariable(PsiVariable variable,
PsiElement context) {
if(context == null){
return false;
}
final PsiType type = variable.getType();
if(type.getArrayDimensions() == 0){
return false;
}
if(VariableAccessUtils.variableIsAssigned(variable, context)){
return false;
}
if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){
return false;
}
if(VariableAccessUtils.variableIsReturned(variable, context)){
return false;
}
return !VariableAccessUtils.variableIsUsedInArrayInitializer(
variable, context);
}
private static boolean arrayContentsAreWritten(PsiVariable variable,
PsiElement context){
if(VariableAccessUtils.arrayContentsAreAssigned(variable, context)){
@@ -124,20 +137,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{
if(initializer != null && !isDefaultArrayInitializer(initializer)){
return true;
}
if(VariableAccessUtils.variableIsAssigned(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsReturned(variable, context)){
return true;
}
if(variableIsWrittenAsMethodArgument(variable, context)) {
return true;
}
return VariableAccessUtils.variableIsUsedInArrayInitializer(variable,
context);
return variableIsWrittenAsMethodArgument(variable, context);
}
private static boolean arrayContentsAreRead(PsiVariable variable,
@@ -145,24 +145,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{
if(VariableAccessUtils.arrayContentsAreAccessed(variable, context)){
return true;
}
final PsiExpression initializer = variable.getInitializer();
if(initializer != null && !isDefaultArrayInitializer(initializer)){
return true;
}
if(VariableAccessUtils.variableIsAssigned(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsReturned(variable, context)){
return true;
}
if(variableIsReadAsMethodArgument(variable, context)) {
return true;
}
return VariableAccessUtils.variableIsUsedInArrayInitializer(variable,
context);
return variableIsReadAsMethodArgument(variable, context);
}
private static boolean isDefaultArrayInitializer(
@@ -170,21 +153,16 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{
if (initializer instanceof PsiNewExpression) {
final PsiNewExpression newExpression =
(PsiNewExpression) initializer;
return newExpression.getArrayInitializer() == null;
} else if (initializer instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression methodCallExpression =
(PsiMethodCallExpression) initializer;
final PsiReferenceExpression methodExpression =
methodCallExpression.getMethodExpression();
final String methodName = methodExpression.getReferenceName();
if (!HardcodedMethodConstants.CLONE.equals(methodName)) {
return false;
}
final PsiExpressionList argumentList =
methodCallExpression.getArgumentList();
final PsiExpression[] expressions =
argumentList.getExpressions();
return expressions.length == 0;
final PsiArrayInitializerExpression arrayInitializer =
newExpression.getArrayInitializer();
return arrayInitializer == null ||
isDefaultArrayInitializer(arrayInitializer);
} else if (initializer instanceof PsiArrayInitializerExpression) {
final PsiArrayInitializerExpression arrayInitializerExpression =
(PsiArrayInitializerExpression) initializer;
final PsiExpression[] initializers =
arrayInitializerExpression.getInitializers();
return initializers.length == 0;
}
return false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2011 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.
@@ -37,9 +37,11 @@ import java.awt.*;
public class MismatchedCollectionQueryUpdateInspection
extends BaseInspection {
@SuppressWarnings({"PublicField"})
public final ExternalizableStringSet queryNames =
new ExternalizableStringSet("copyInto", "drainTo", "propertyNames",
"save", "store", "write");
@SuppressWarnings({"PublicField"})
public final ExternalizableStringSet updateNames =
new ExternalizableStringSet("add", "clear", "drainTo", "insert",
"load", "offer", "poll", "push", "put", "remove", "replace",
@@ -140,16 +142,16 @@ public class MismatchedCollectionQueryUpdateInspection
if(argumentList == null){
return false;
}
final PsiExpression[] expressions = argumentList.getExpressions();
for(final PsiExpression arg : expressions){
final PsiType argType = arg.getType();
if(argType == null){
final PsiExpression[] arguments = argumentList.getExpressions();
for(final PsiExpression argument : arguments){
final PsiType argumentType = argument.getType();
if(argumentType == null){
return false;
}
if(CollectionUtils.isCollectionClassOrInterface(argType)){
if(CollectionUtils.isCollectionClassOrInterface(argumentType)){
return false;
}
if(argType instanceof PsiArrayType){
if(argumentType instanceof PsiArrayType){
return false;
}
}
@@ -165,11 +167,7 @@ public class MismatchedCollectionQueryUpdateInspection
return;
}
final PsiClass containingClass = PsiUtil.getTopLevelClass(field);
if(containingClass == null){
return;
}
final PsiType type = field.getType();
if(!CollectionUtils.isCollectionClassOrInterface(type)){
if (!checkVariable(field, containingClass)) {
return;
}
final boolean written =
@@ -182,16 +180,13 @@ public class MismatchedCollectionQueryUpdateInspection
registerFieldError(field, Boolean.valueOf(written));
}
@Override public void visitLocalVariable(@NotNull PsiLocalVariable variable){
@Override public void visitLocalVariable(
@NotNull PsiLocalVariable variable){
super.visitLocalVariable(variable);
final PsiCodeBlock codeBlock =
PsiTreeUtil.getParentOfType(variable,
PsiCodeBlock.class);
if(codeBlock == null){
return;
}
final PsiType type = variable.getType();
if(!CollectionUtils.isCollectionClassOrInterface(type)){
if (!checkVariable(variable, codeBlock)) {
return;
}
final boolean written =
@@ -203,6 +198,29 @@ public class MismatchedCollectionQueryUpdateInspection
}
}
private boolean checkVariable(PsiVariable variable,
PsiElement context) {
if (context == null) {
return false;
}
final PsiType type = variable.getType();
if(!CollectionUtils.isCollectionClassOrInterface(type)){
return false;
}
if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){
return false;
}
if(VariableAccessUtils.variableIsReturned(variable, context)){
return false;
}
if(VariableAccessUtils.variableIsPassedAsMethodArgument(variable,
context)){
return false;
}
return !VariableAccessUtils.variableIsUsedInArrayInitializer(
variable, context);
}
private boolean collectionContentsAreUpdated(
PsiVariable variable, PsiElement context){
if(collectionUpdateCalled(variable, context)){
@@ -224,21 +242,7 @@ public class MismatchedCollectionQueryUpdateInspection
}
}
}
if(VariableAccessUtils.variableIsAssigned(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsReturned(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsPassedAsMethodArgument(variable,
context)){
return true;
}
return VariableAccessUtils.variableIsUsedInArrayInitializer(variable,
context);
return VariableAccessUtils.variableIsAssigned(variable, context);
}
private boolean collectionContentsAreQueried(
@@ -246,26 +250,7 @@ public class MismatchedCollectionQueryUpdateInspection
if(collectionQueryCalled(variable, context)){
return true;
}
final PsiExpression initializer = variable.getInitializer();
if(initializer != null &&
!isEmptyCollectionInitializer(initializer)){
return true;
}
if(collectionQueriedByAssignment(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsReturned(variable, context)){
return true;
}
if(VariableAccessUtils.variableIsPassedAsMethodArgument(variable,
context)){
return true;
}
return VariableAccessUtils.variableIsUsedInArrayInitializer(variable,
context);
return collectionQueriedByAssignment(variable, context);
}
private boolean collectionQueryCalled(PsiVariable variable,
@@ -0,0 +1,374 @@
/*
* Copyright 2011 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.bugs;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.TypeUtils;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
public class MismatchedStringBuilderQueryUpdateInspection extends BaseInspection {
@NonNls
private static final Set<String> returnSelfNames = new HashSet();
static {
returnSelfNames.add("append");
returnSelfNames.add("appendCodePoint");
returnSelfNames.add("delete");
returnSelfNames.add("deleteCharAt");
returnSelfNames.add("insert");
returnSelfNames.add("replace");
returnSelfNames.add("reverse");
}
@Override
@NotNull
public String getID(){
return "MismatchedQueryAndUpdateOfStringBuilder";
}
@Nls
@NotNull
@Override
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"mismatched.string.builder.query.update.display.name");
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
final boolean updated = ((Boolean)infos[0]).booleanValue();
final PsiType type = (PsiType)infos[1]; //"StringBuilder";
if(updated){
return InspectionGadgetsBundle.message(
"mismatched.string.builder.updated.problem.descriptor",
type.getPresentableText());
} else{
return InspectionGadgetsBundle.message(
"mismatched.string.builder.queried.problem.descriptor",
type.getPresentableText());
}
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
public boolean runForWholeFile() {
return true;
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new MismatchedQueryAndUpdateOfStringBuilderVisitor();
}
private static class MismatchedQueryAndUpdateOfStringBuilderVisitor
extends BaseInspectionVisitor {
@Override
public void visitField(PsiField field) {
super.visitField(field);
if (!field.hasModifierProperty(PsiModifier.PRIVATE)) {
return;
}
final PsiClass containingClass = PsiUtil.getTopLevelClass(field);
if (!checkVariable(field, containingClass)) {
return;
}
final boolean queried =
stringBuilderContentsAreQueried(field, containingClass);
final boolean updated =
stringBuilderContentsAreUpdated(field, containingClass);
if (queried == updated) {
return;
}
registerFieldError(field, Boolean.valueOf(updated),
field.getType());
}
@Override
public void visitLocalVariable(PsiLocalVariable variable) {
super.visitLocalVariable(variable);
final PsiCodeBlock codeBlock =
PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
if (!checkVariable(variable, codeBlock)) {
return;
}
final boolean queried =
stringBuilderContentsAreQueried(variable, codeBlock);
final boolean updated =
stringBuilderContentsAreUpdated(variable, codeBlock);
if (queried == updated) {
return;
}
registerVariableError(variable, Boolean.valueOf(updated),
variable.getType());
}
private static boolean checkVariable(PsiVariable variable,
PsiElement context) {
if(context == null){
return false;
}
if (!TypeUtils.variableHasTypeOrSubtype(variable,
"java.lang.AbstractStringBuilder")) {
return false;
}
if(VariableAccessUtils.variableIsAssigned(variable, context)){
return false;
}
if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){
return false;
}
if(VariableAccessUtils.variableIsReturned(variable, context)){
return false;
}
return !VariableAccessUtils.variableIsUsedInArrayInitializer(
variable, context);
}
private static boolean stringBuilderContentsAreUpdated(
PsiVariable variable, PsiElement context) {
final PsiExpression initializer = variable.getInitializer();
if (initializer != null && !isDefaultConstructorCall(initializer)) {
return true;
}
return isStringBuilderUpdated(variable, context);
}
private static boolean stringBuilderContentsAreQueried(
PsiVariable variable, PsiElement context) {
return isStringBuilderQueried(variable, context);
}
private static boolean isDefaultConstructorCall(
PsiExpression initializer) {
if (!(initializer instanceof PsiNewExpression)) {
return false;
}
final PsiNewExpression newExpression =
(PsiNewExpression) initializer;
final PsiJavaCodeReferenceElement classReference =
newExpression.getClassReference();
if (classReference == null) {
return false;
}
final PsiElement target = classReference.resolve();
if (!(target instanceof PsiClass)) {
return false;
}
final PsiClass aClass = (PsiClass) target;
final String qualifiedName = aClass.getQualifiedName();
if (!"java.lang.StringBuilder".equals(qualifiedName) &&
!"java.lang.StringBuffer".equals(qualifiedName)) {
return false;
}
final PsiExpressionList argumentList =
newExpression.getArgumentList();
if (argumentList == null) {
return false;
}
final PsiExpression[] arguments = argumentList.getExpressions();
if (arguments.length == 0) {
return true;
}
final PsiExpression argument = arguments[0];
final PsiType argumentType = argument.getType();
return PsiType.INT.equals(argumentType);
}
}
public static boolean isStringBuilderUpdated(PsiVariable variable,
PsiElement context) {
final StringBuilderUpdateCalledVisitor visitor =
new StringBuilderUpdateCalledVisitor(variable);
context.accept(visitor);
return visitor.isUpdated();
}
private static class StringBuilderUpdateCalledVisitor
extends JavaRecursiveElementVisitor {
@NonNls
private static final Set<String> updateNames = new HashSet();
static {
updateNames.add("append");
updateNames.add("appendCodePoint");
updateNames.add("delete");
updateNames.add("delete");
updateNames.add("deleteCharAt");
updateNames.add("insert");
updateNames.add("replace");
updateNames.add("setCharAt");
}
private final PsiVariable variable;
boolean updated = false;
public StringBuilderUpdateCalledVisitor(PsiVariable variable) {
this.variable = variable;
}
public boolean isUpdated() {
return updated;
}
@Override
public void visitMethodCallExpression(
PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
if (updated) {
return;
}
super.visitMethodCallExpression(expression);
final PsiReferenceExpression methodExpression =
expression.getMethodExpression();
final String name = methodExpression.getReferenceName();
if (!updateNames.contains(name)) {
return;
}
final PsiExpression qualifierExpression =
methodExpression.getQualifierExpression();
if (hasReferenceToVariable(variable, qualifierExpression)) {
updated = true;
}
}
}
public static boolean isStringBuilderQueried(PsiVariable variable,
PsiElement context) {
final StringBuilderQueryCalledVisitor visitor =
new StringBuilderQueryCalledVisitor(variable);
context.accept(visitor);
return visitor.isQueried();
}
private static class StringBuilderQueryCalledVisitor
extends JavaRecursiveElementVisitor {
@NonNls
private static final Set<String> queryNames = new HashSet();
static {
queryNames.add("toString");
queryNames.add("indexOf");
queryNames.add("lastIndexOf");
queryNames.add("capacity");
queryNames.add("charAt");
queryNames.add("codePointAt");
queryNames.add("codePointBefore");
queryNames.add("codePointCount");
queryNames.add("equals");
queryNames.add("getChars");
queryNames.add("hashCode");
queryNames.add("length");
queryNames.add("offsetByCodePoints");
queryNames.add("subSequence");
queryNames.add("substring");
}
private final PsiVariable variable;
private boolean queried = false;
private StringBuilderQueryCalledVisitor(PsiVariable variable) {
this.variable = variable;
}
public boolean isQueried() {
return queried;
}
@Override public void visitElement(@NotNull PsiElement element){
if (queried) {
return;
}
super.visitElement(element);
}
@Override
public void visitMethodCallExpression(
PsiMethodCallExpression expression) {
if (queried) {
return;
}
super.visitMethodCallExpression(expression);
final PsiReferenceExpression methodExpression =
expression.getMethodExpression();
final String name = methodExpression.getReferenceName();
if (!queryNames.contains(name)) {
return;
}
final PsiExpression qualifierExpression =
methodExpression.getQualifierExpression();
if (hasReferenceToVariable(variable, qualifierExpression)) {
queried = true;
}
}
}
private static boolean hasReferenceToVariable(PsiVariable variable,
PsiElement element) {
if (element instanceof PsiReferenceExpression) {
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression) element;
final PsiElement target = referenceExpression.resolve();
if (variable.equals(target)) {
return true;
}
} else if (element instanceof PsiParenthesizedExpression) {
final PsiParenthesizedExpression parenthesizedExpression =
(PsiParenthesizedExpression) element;
final PsiExpression expression =
parenthesizedExpression.getExpression();
return hasReferenceToVariable(variable, expression);
} else if (element instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression methodCallExpression =
(PsiMethodCallExpression) element;
final PsiReferenceExpression methodExpression =
methodCallExpression.getMethodExpression();
final String name = methodExpression.getReferenceName();
if (returnSelfNames.contains(name)) {
return hasReferenceToVariable(variable,
methodExpression.getQualifierExpression());
}
} else if (element instanceof PsiConditionalExpression) {
final PsiConditionalExpression conditionalExpression =
(PsiConditionalExpression) element;
final PsiExpression thenExpression =
conditionalExpression.getThenExpression();
if (hasReferenceToVariable(variable, thenExpression)) {
return true;
}
final PsiExpression elseExpression =
conditionalExpression.getElseExpression();
return hasReferenceToVariable(variable, elseExpression);
}
return false;
}
}
@@ -0,0 +1,9 @@
<html>
<body>
This inspection reports any StringBuilder or StringBuffer fields or variables whose contents are read but not written,
or written but not read. Such mismatched reads and writes are pointless, and probably indicate
dead, incomplete or erroneous code.
<p>
<small>New in 10.5, Powered by InspectionGadgets</small>
</body>
</html>
@@ -85,4 +85,19 @@ class Test{
array[0][1]++;
System.out.println(array[0][1]);
}
void foo1() {
final int[] barzoom = {};
barzoom[2] = 3;
}
void foo2() {
final int[] barzoom = new int[]{};
barzoom[2] = 3;
}
void foo3(Object[] otherArr) {
Object[] arr = otherArr.clone();
for (int i = 0; i < 10; i++) arr[i] = i;
}
}
@@ -42,4 +42,33 @@
<description>Contents of array &lt;code&gt;foo&lt;/code&gt; are written to, but never read #loc</description>
</problem>
<problem>
<file>MismatchedArrayReadWrite.java</file>
<line>90</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Mismatched read and write of array</problem_class>
<description>Contents of array &lt;code&gt;barzoom&lt;/code&gt; are written to, but never read #loc</description>
</problem>
<problem>
<file>MismatchedArrayReadWrite.java</file>
<line>100</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Mismatched read and write of array</problem_class>
<description>Contents of array &lt;code&gt;arr&lt;/code&gt; are written to, but never read #loc</description>
</problem>
<problem>
<file>MismatchedArrayReadWrite.java</file>
<line>95</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Mismatched read and write of array</problem_class>
<description>Contents of array &lt;code&gt;barzoom&lt;/code&gt; are written to, but never read #loc</description>
</problem>
<problem>
<file>MismatchedArrayReadWrite.java</file>
<line>61</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Mismatched read and write of array</problem_class>
<description>Contents of array &lt;code&gt;rowData&lt;/code&gt; are written to, but never read #loc</description>
</problem>
</problems>
@@ -21,14 +21,8 @@ import com.intellij.facet.ProjectFacetManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompileStatusNotification;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import org.jetbrains.android.exportSignedPackage.CheckModulePanel;
import org.jetbrains.android.exportSignedPackage.ExportSignedPackageWizard;
import org.jetbrains.android.facet.AndroidFacet;
@@ -51,55 +45,18 @@ public class ExportSignedPackageAction extends AnAction {
e.getPresentation().setEnabled(project != null && ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID).size() > 0);
}
private static void makeProjectIfNeccessaryAndRun(final Project project, final Runnable afterAction) {
final CompilerManager manager = CompilerManager.getInstance(project);
final CompileScope compileScope = manager.createProjectCompileScope(project);
if (!manager.isUpToDate(compileScope)) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
final int result = Messages.showYesNoDialog(project, AndroidBundle.message("android.export.signed.package.make.question"),
AndroidBundle.message("android.export.signed.package.action.text"),
Messages.getQuestionIcon());
if (result == 0) {
manager.make(compileScope, new CompileStatusNotification() {
public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
if (!aborted && errors == 0) {
afterAction.run();
}
}
});
}
else {
afterAction.run();
}
}
});
}
else {
ApplicationManager.getApplication().invokeLater(afterAction);
}
}
@Override
public void actionPerformed(AnActionEvent e) {
final Project project = e.getData(DataKeys.PROJECT);
assert project != null;
final Runnable exportRunnable = new Runnable() {
public void run() {
List<AndroidFacet> facets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID);
assert facets.size() > 0;
if (facets.size() == 1) {
if (!checkFacet(facets.get(0))) return;
}
ExportSignedPackageWizard wizard = new ExportSignedPackageWizard(project, facets);
wizard.show();
}
};
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
makeProjectIfNeccessaryAndRun(project, exportRunnable);
}
});
List<AndroidFacet> facets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID);
assert facets.size() > 0;
if (facets.size() == 1) {
if (!checkFacet(facets.get(0))) return;
}
ExportSignedPackageWizard wizard = new ExportSignedPackageWizard(project, facets);
wizard.show();
}
private static boolean checkFacet(final AndroidFacet facet) {
@@ -216,6 +216,11 @@ public class NewAndroidComponentDialog extends DialogWrapper {
return myNameField;
}
@Override
protected String getHelpId() {
return "reference.new.android.component";
}
@Override
protected JComponent createCenterPanel() {
return myPanel;
@@ -114,7 +114,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
try {
Map<CompilerMessageCategory, List<String>> messages = AndroidApt
.compile(aptItem.myAndroidTarget, aptItem.myManifestPath, aptItem.mySourceRootPath, aptItem.myResourcesPaths,
.compile(aptItem.myAndroidTarget, aptItem.myManifestFile.getPath(), aptItem.mySourceRootPath, aptItem.myResourcesPaths,
aptItem.myAssetsPath, aptItem.myCustomPackage ? aptItem.myPackage : null
);
AndroidCompileUtil.addMessages(context, messages);
@@ -169,7 +169,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
final static class AptGenerationItem implements GenerationItem {
final Module myModule;
final String myManifestPath;
final VirtualFile myManifestFile;
final String[] myResourcesPaths;
final String myAssetsPath;
final String mySourceRootPath;
@@ -179,7 +179,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
final boolean myCustomPackage;
private AptGenerationItem(@NotNull Module module,
@NotNull String manifestPath,
@NotNull VirtualFile manifestFile,
@NotNull String[] resourcesPaths,
@Nullable String assetsPath,
@NotNull String sourceRootPath,
@@ -187,7 +187,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
@NotNull String aPackage,
boolean customPackage) {
myModule = module;
myManifestPath = manifestPath;
myManifestFile = manifestFile;
myResourcesPaths = resourcesPaths;
myAssetsPath = assetsPath;
mySourceRootPath = sourceRootPath;
@@ -290,12 +290,11 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
AndroidCompileUtil.createSourceRootIfNotExist(sourceRootPath, module);
String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null;
String manifestPath = manifestFile.getPath();
items.add(new AptGenerationItem(module, manifestPath, resPaths, assetsDirPath, sourceRootPath, target,
items.add(new AptGenerationItem(module, manifestFile, resPaths, assetsDirPath, sourceRootPath, target,
packageName, false));
for (String libPackage : AndroidUtils.getDepLibsPackages(module)) {
items.add(new AptGenerationItem(module, manifestPath, resPaths, assetsDirPath, sourceRootPath, target,
items.add(new AptGenerationItem(module, manifestFile, resPaths, assetsDirPath, sourceRootPath, target,
libPackage, true));
}
}
@@ -34,11 +34,9 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
@@ -64,10 +62,17 @@ public class AndroidCompileUtil {
private static final Pattern ourMessagePattern = Pattern.compile("(.+):(\\d+):.+");
private static final Key<Boolean> RELEASE_BUILD_KEY = new Key<Boolean>("RELEASE_BUILD_KEY");
private AndroidCompileUtil() {
}
static void addMessages(final CompileContext context, final Map<CompilerMessageCategory, List<String>> messages) {
addMessages(context, messages, null);
}
static void addMessages(final CompileContext context, final Map<CompilerMessageCategory, List<String>> messages,
@Nullable final Map<VirtualFile, VirtualFile> presentableFilesMap) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (context.getProject().isDisposed()) return;
@@ -80,7 +85,7 @@ public class AndroidCompileUtil {
if (matcher.matches()) {
String fileName = matcher.group(1);
if (new File(fileName).exists()) {
url = "file://" + fileName;
url = getPresentableFile("file://" + fileName, presentableFilesMap);
line = Integer.parseInt(matcher.group(2));
}
}
@@ -91,6 +96,25 @@ public class AndroidCompileUtil {
});
}
@NotNull
private static String getPresentableFile(@NotNull String url, @Nullable Map<VirtualFile, VirtualFile> presentableFilesMap) {
final VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url);
if (file == null) {
return url;
}
if (presentableFilesMap == null) {
return url;
}
for (Map.Entry<VirtualFile, VirtualFile> entry : presentableFilesMap.entrySet()) {
if (file == entry.getValue()) {
return entry.getKey().getUrl();
}
}
return url;
}
private static void collectChildrenRecursively(@NotNull VirtualFile root,
@NotNull VirtualFile anchor,
@NotNull Collection<VirtualFile> result) {
@@ -364,4 +388,13 @@ public class AndroidCompileUtil {
RunConfiguration runConfiguration = CompileStepBeforeRun.getRunConfiguration(context);
return !(runConfiguration instanceof JUnitConfiguration);
}
public static boolean isReleaseBuild(@NotNull CompileContext context) {
final Boolean value = context.getCompileScope().getUserData(RELEASE_BUILD_KEY);
return value != null && value.booleanValue();
}
public static void setReleaseBuild(@NotNull CompileScope compileScope) {
compileScope.putUserData(RELEASE_BUILD_KEY, Boolean.TRUE);
}
}
@@ -63,7 +63,7 @@ public class AndroidDexCompilerSettingsFactory implements CompilerSettingsFactor
@Override
public String getHelpTopic() {
return null;
return "settings.android.dx.compiler";
}
@Override
@@ -48,6 +48,8 @@ import java.util.*;
*/
public class AndroidPackagingCompiler implements PackagingCompiler {
public static final String UNSIGNED_SUFFIX = ".unsigned";
public void processOutdatedItem(CompileContext context, String url, @Nullable ValidityState state) {
}
@@ -125,13 +127,12 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
AndroidBundle.message("android.compilation.error.apk.path.not.specified", module.getName()), null, -1, -1);
continue;
}
AptPackagingItem item =
new AptPackagingItem(sdkPath, manifestFile, resPackagePath, outputPath, configuration.GENERATE_UNSIGNED_APK, module);
item.setNativeLibsFolders(collectNativeLibsFolders(facet));
item.setClassesDexPath(classesDexPath);
item.setSourceRoots(sourceRoots);
item.setExternalLibraries(externalJars);
items.add(item);
items.add(createItem(module, facet, manifestFile, sourceRoots, externalJars, resPackagePath, classesDexPath, sdkPath,
outputPath, false));
items.add(createItem(module, facet, manifestFile, sourceRoots, externalJars,
resPackagePath + AndroidResourcesPackagingCompiler.RELEASE_SUFFIX, classesDexPath, sdkPath,
outputPath + UNSIGNED_SUFFIX, true));
}
}
}
@@ -139,6 +140,24 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
return items.toArray(new ProcessingItem[items.size()]);
}
private static AptPackagingItem createItem(Module module,
AndroidFacet facet,
VirtualFile manifestFile,
VirtualFile[] sourceRoots,
VirtualFile[] externalJars,
String resPackagePath,
String classesDexPath,
String sdkPath,
String outputPath,
boolean unsigned) {
AptPackagingItem item = new AptPackagingItem(sdkPath, manifestFile, resPackagePath, outputPath, unsigned, module);
item.setNativeLibsFolders(collectNativeLibsFolders(facet));
item.setClassesDexPath(classesDexPath);
item.setSourceRoots(sourceRoots);
item.setExternalLibraries(externalJars);
return item;
}
@NotNull
private static VirtualFile[] collectNativeLibsFolders(AndroidFacet facet) {
List<VirtualFile> result = new ArrayList<VirtualFile>();
@@ -179,11 +198,13 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
continue;
}
if (!shouldGenerateApk(item.myModule, context, item.isUnsigned())) {
continue;
}
try {
String[] externalLibPaths = getPaths(item.getExternalLibraries());
final Map<CompilerMessageCategory, List<String>> apkuBuilderMessages = AndroidApkBuilder
final String[] externalLibPaths = getPaths(item.getExternalLibraries());
final Map<CompilerMessageCategory, List<String>> messages = AndroidApkBuilder
.execute(item.mySdkPath,
item.getResPackagePath(),
item.getClassesDexPath(),
@@ -191,9 +212,8 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
externalLibPaths,
item.getNativeLibsFolders(),
item.getFinalPath(),
item.isGenerateUnsignedApk());
AndroidCompileUtil.addMessages(context, apkuBuilderMessages);
item.isUnsigned());
AndroidCompileUtil.addMessages(context, messages);
}
catch (final IOException e) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@@ -210,6 +230,29 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
return result.toArray(new ProcessingItem[result.size()]);
}
public static boolean shouldGenerateApk(Module module, CompileContext context, boolean unsigned) {
final boolean releaseBuild = AndroidCompileUtil.isReleaseBuild(context);
if (!unsigned) {
return !releaseBuild;
}
final AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet == null) {
return true;
}
if (releaseBuild) {
return true;
}
if (facet.getConfiguration().GENERATE_UNSIGNED_APK) {
return true;
}
return false;
}
@NotNull
public String getDescription() {
return "Android Packaging Compiler";
@@ -232,20 +275,20 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
private VirtualFile[] myNativeLibsFolders;
private VirtualFile[] mySourceRoots;
private VirtualFile[] myExternalLibraries;
private final boolean myGenerateUnsignedApk;
private final boolean myUnsigned;
private final Module myModule;
private AptPackagingItem(String sdkPath,
@NotNull VirtualFile manifestFile,
@NotNull String resPackagePath,
@NotNull String finalPath,
boolean generateUnsignedApk,
boolean unsigned,
@NotNull Module module) {
mySdkPath = sdkPath;
myManifestFile = manifestFile;
myResPackagePath = resPackagePath;
myFinalPath = finalPath;
myGenerateUnsignedApk = generateUnsignedApk;
myUnsigned = unsigned;
myModule = module;
}
@@ -302,12 +345,12 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
@Nullable
public ValidityState getValidityState() {
return new MyValidityState(myManifestFile, myResPackagePath, myClassesDexPath, myFinalPath, myGenerateUnsignedApk, mySourceRoots,
return new MyValidityState(myManifestFile, myResPackagePath, myClassesDexPath, myFinalPath, myUnsigned, mySourceRoots,
myExternalLibraries, myNativeLibsFolders);
}
public boolean isGenerateUnsignedApk() {
return myGenerateUnsignedApk;
public boolean isUnsigned() {
return myUnsigned;
}
}
@@ -17,21 +17,30 @@ package org.jetbrains.android.compiler;
import com.android.sdklib.IAndroidTarget;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.android.compiler.tools.AndroidApt;
import org.jetbrains.android.dom.manifest.Application;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidFacetConfiguration;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -39,6 +48,10 @@ import java.util.Map;
* @author Eugene.Kudelevsky
*/
public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCompiler {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidResourcesPackagingCompiler");
public static final String RELEASE_SUFFIX = ".release";
@NotNull
@Override
public ProcessingItem[] getProcessingItems(CompileContext context) {
@@ -65,7 +78,9 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom
context.addMessage(CompilerMessageCategory.WARNING, "Resource directory not found for module " + module.getName(),
null, -1, -1);
}
items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath));
items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath, false));
items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath + RELEASE_SUFFIX, true));
}
}
}
@@ -92,12 +107,32 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom
continue;
}
if (!AndroidPackagingCompiler.shouldGenerateApk(item.myModule, context, item.myReleasePackage)) {
continue;
}
final VirtualFile preprocessedManifestFile;
try {
preprocessedManifestFile = item.myReleasePackage
? item.myManifestFile
: copyManifestAndSetDebuggableToTrue(item.myModule, item.myManifestFile);
}
catch (IOException e) {
LOG.info(e);
context.addMessage(CompilerMessageCategory.ERROR, "Cannot preprocess AndroidManifest.xml for debug build",
item.myManifestFile.getUrl(), -1, -1);
continue;
}
final Map<VirtualFile, VirtualFile> presentableFilesMap = Collections.singletonMap(item.myManifestFile, preprocessedManifestFile);
try {
Map<CompilerMessageCategory, List<String>> messages = AndroidApt.packageResources(item.myAndroidTarget,
item.myManifestFile.getPath(),
item.myResourceDirPaths, item.myAssetsDirPath,
preprocessedManifestFile.getPath(),
item.myResourceDirPaths,
item.myAssetsDirPath,
item.myOutputPath);
AndroidCompileUtil.addMessages(context, messages);
AndroidCompileUtil.addMessages(context, messages, presentableFilesMap);
}
catch (final IOException e) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@@ -114,6 +149,58 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom
return result.toArray(new ProcessingItem[result.size()]);
}
private static VirtualFile copyManifestAndSetDebuggableToTrue(@NotNull final Module module, @NotNull final VirtualFile manifestFile)
throws IOException {
final File dir = FileUtil.createTempDirectory("android_manifest_copy", "tmp");
final VirtualFile vDir = LocalFileSystem.getInstance().findFileByIoFile(dir);
if (vDir == null) {
throw new IOException("Cannot create temp directory for manifest copy");
}
final VirtualFile[] manifestFileCopy = new VirtualFile[1];
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
manifestFileCopy[0] = manifestFile.copy(module.getProject(), vDir, manifestFile.getName());
}
catch (IOException e) {
LOG.info(e);
return;
}
if (manifestFileCopy[0] == null) {
return;
}
final Manifest manifestInCopy = AndroidUtils.loadDomElement(module, manifestFileCopy[0], Manifest.class);
if (manifestInCopy == null) {
return;
}
final Application applicationInCopy = manifestInCopy.getApplication();
if (applicationInCopy == null) {
return;
}
applicationInCopy.getDebuggable().setValue(Boolean.TRUE.toString());
}
});
ApplicationManager.getApplication().saveAll();
}
}, ModalityState.defaultModalityState());
if (manifestFileCopy[0] == null) {
throw new IOException("Cannot copy manifest file to " + vDir.getPath());
}
return manifestFileCopy[0];
}
@NotNull
@Override
public String getDescription() {
@@ -139,13 +226,15 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom
final String myOutputPath;
private final boolean myFileExists;
private final boolean myReleasePackage;
private MyItem(Module module,
IAndroidTarget androidTarget,
VirtualFile manifestFile,
String[] resourceDirPaths,
String assetsDirPath,
String outputPath) {
String outputPath,
boolean releasePackage) {
myModule = module;
myAndroidTarget = androidTarget;
myManifestFile = manifestFile;
@@ -153,6 +242,7 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom
myAssetsDirPath = assetsDirPath;
myOutputPath = outputPath;
myFileExists = new File(outputPath).exists();
myReleasePackage = releasePackage;
}
@NotNull
@@ -164,20 +254,23 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom
@Override
public ValidityState getValidityState() {
return new MyValidityState(myModule, myFileExists);
return new MyValidityState(myModule, myFileExists, myReleasePackage);
}
}
private static class MyValidityState extends ResourcesValidityState {
private final boolean myOutputFileExists;
private final boolean myReleaseBuild;
public MyValidityState(Module module, boolean outputFileExists) {
public MyValidityState(Module module, boolean outputFileExists, boolean releaseBuild) {
super(module);
myOutputFileExists = outputFileExists;
myReleaseBuild = releaseBuild;
}
public MyValidityState(DataInput is) throws IOException {
super(is);
myReleaseBuild = is.readBoolean();
myOutputFileExists = true;
}
@@ -186,10 +279,20 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom
if (!(otherState instanceof MyValidityState)) {
return false;
}
if (myOutputFileExists != ((MyValidityState)otherState).myOutputFileExists) {
final MyValidityState otherState1 = (MyValidityState)otherState;
if (myOutputFileExists != otherState1.myOutputFileExists) {
return false;
}
if (myReleaseBuild != otherState1.myReleaseBuild) {
return false;
}
return super.equalsTo(otherState);
}
@Override
public void save(DataOutput os) throws IOException {
super.save(os);
os.writeBoolean(myReleaseBuild);
}
}
}
@@ -49,7 +49,7 @@ public class ResourcesValidityState implements ValidityState {
IAndroidTarget target = platform != null ? platform.getTarget() : null;
myAndroidTargetName = target != null ? target.getFullName() : "";
VirtualFile manifestFile = AndroidRootUtil.getManifestFile(module);
VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet);
if (manifestFile != null) {
myResourceTimestamps.put(manifestFile.getPath(), manifestFile.getTimeStamp());
}
@@ -43,16 +43,13 @@ import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static com.intellij.openapi.compiler.CompilerMessageCategory.ERROR;
import static com.intellij.openapi.compiler.CompilerMessageCategory.INFORMATION;
import static com.intellij.openapi.compiler.CompilerMessageCategory.WARNING;
import static com.intellij.openapi.compiler.CompilerMessageCategory.*;
/**
* @author yole
*/
public class AndroidApkBuilder {
private static final String UNALIGNED_SUFFIX = ".unaligned";
private static final String UNSIGNED_SUFFIX = ".unsigned";
private AndroidApkBuilder() {
}
@@ -114,18 +111,13 @@ public class AndroidApkBuilder {
@NotNull String[] externalJars,
@NotNull VirtualFile[] nativeLibsFolders,
@NotNull String finalApk,
boolean generateUnsignedApk) throws IOException {
String unsignedApk = finalApk + UNSIGNED_SUFFIX;
Map<CompilerMessageCategory, List<String>> map;
if (generateUnsignedApk) {
map = filterUsingKeystoreMessages(
finalPackage(resPackagePath, dexPath, sourceRoots, externalJars, nativeLibsFolders, unsignedApk, false));
}
else {
map = new HashMap<CompilerMessageCategory, List<String>>();
boolean unsigned) throws IOException {
if (unsigned) {
return filterUsingKeystoreMessages(
finalPackage(resPackagePath, dexPath, sourceRoots, externalJars, nativeLibsFolders, finalApk, false));
}
final Map<CompilerMessageCategory, List<String>> map = new HashMap<CompilerMessageCategory, List<String>>();
final String zipAlignPath = sdkPath + File.separator + AndroidUtils.toolPath(SdkConstants.FN_ZIPALIGN);
boolean withAlignment = new File(zipAlignPath).exists();
String unalignedApk = finalApk + UNALIGNED_SUFFIX;
@@ -15,6 +15,7 @@
*/
package org.jetbrains.android.dom.converters;
import com.intellij.openapi.module.Module;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.xml.ConvertContext;
@@ -41,8 +42,11 @@ public class ConstantFieldConverter extends ResolvingConverter<String> {
LookupClass lookupClass = element.getAnnotation(LookupClass.class);
LookupPrefix lookupPrefix = element.getAnnotation(LookupPrefix.class);
if (lookupClass != null && lookupPrefix != null) {
PsiClass psiClass = JavaPsiFacade.getInstance(context.getPsiManager().getProject()).findClass(lookupClass.value(),
GlobalSearchScope.allScope(context.getModule().getProject()));
final Module module = context.getModule();
final GlobalSearchScope scope = module != null ?
GlobalSearchScope.allScope(module.getProject()) :
context.getInvocationElement().getResolveScope();
PsiClass psiClass = JavaPsiFacade.getInstance(context.getPsiManager().getProject()).findClass(lookupClass.value(), scope);
if (psiClass != null) {
PsiField[] psiFields = psiClass.getFields();
for(PsiField field: psiFields) {
@@ -77,7 +77,10 @@ public class PackageClassConverter extends ResolvingConverter<PsiClass> implemen
className = packageName + "." + s;
}
JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getPsiManager().getProject());
GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(context.getModule());
final Module module = context.getModule();
GlobalSearchScope scope = module != null
? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)
: context.getInvocationElement().getResolveScope();
PsiClass psiClass = facade.findClass(className, scope);
if (psiClass == null) {
psiClass = facade.findClass(s, scope);
@@ -264,7 +267,9 @@ public class PackageClassConverter extends ResolvingConverter<PsiClass> implemen
if (!myStartsWithPoint) {
final PsiElement element = myIsPackage ?
facade.findPackage(value) :
facade.findClass(value, myModule.getModuleWithDependenciesScope());
facade.findClass(value, myModule != null
? myModule.getModuleWithDependenciesScope()
: myElement.getResolveScope());
if (element != null) {
return element;
@@ -275,7 +280,9 @@ public class PackageClassConverter extends ResolvingConverter<PsiClass> implemen
if (relativeName != null) {
return myIsPackage ?
facade.findPackage(relativeName) :
facade.findClass(relativeName, myModule.getModuleWithDependenciesScope());
facade.findClass(relativeName, myModule != null
? myModule.getModuleWithDependenciesScope()
: myElement.getResolveScope());
}
return null;
}
@@ -16,6 +16,7 @@
package org.jetbrains.android.dom.manifest;
import com.intellij.psi.PsiClass;
import com.intellij.util.xml.Attribute;
import com.intellij.util.xml.Convert;
import com.intellij.util.xml.ExtendClass;
import org.jetbrains.android.dom.AndroidAttributeValue;
@@ -53,6 +54,7 @@ public interface Application extends ManifestElement {
@Convert(PackageClassConverter.class)
@ExtendClass("android.app.Activity")
@Attribute("manageSpaceActivity")
AndroidAttributeValue<PsiClass> getManageSpaceActivity();
@Convert(PackageClassConverter.class)
@@ -17,6 +17,7 @@ package org.jetbrains.android.dom.manifest;
import com.android.sdklib.SdkConstants;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.xml.DomFileDescription;
import org.jetbrains.android.facet.AndroidFacet;
@@ -40,7 +41,8 @@ public class ManifestDomFileDescription extends DomFileDescription<Manifest> {
if (!file.getName().equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) {
return false;
}
return AndroidFacet.getInstance(file) != null;
final Module module = ModuleUtil.findModuleForPsiElement(file);
return module == null || AndroidFacet.getInstance(module) != null;
}
protected void initializeFileDescription() {
@@ -27,7 +27,10 @@ import com.intellij.execution.process.ProcessEvent;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.wizard.CommitStepException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompilerPaths;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompileStatusNotification;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
@@ -38,6 +41,8 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.android.compiler.AndroidCompileUtil;
import org.jetbrains.android.compiler.AndroidPackagingCompiler;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidBundle;
@@ -166,7 +171,8 @@ class ApkStep extends ExportSignedPackageWizardStep {
assert certificate != null;
SignedJarBuilder builder = new SignedJarBuilder(fos, privateKey, certificate);
Module module = myWizard.getFacet().getModule();
String srcApkPath = CompilerPaths.getModuleOutputPath(module, false) + '/' + module.getName() + ".apk";
//String srcApkPath = CompilerPaths.getModuleOutputPath(module, false) + '/' + module.getName() + ".apk";
String srcApkPath = myWizard.getFacet().getApkPath() + AndroidPackagingCompiler.UNSIGNED_SUFFIX;
FileInputStream fis = new FileInputStream(new File(FileUtil.toSystemDependentName(srcApkPath)));
try {
builder.writeZip(fis, null);
@@ -255,11 +261,23 @@ class ApkStep extends ExportSignedPackageWizardStep {
catch (Exception e) {
throw new CommitStepException(e.getMessage());
}
String title = AndroidBundle.message("android.extract.package.task.title");
ProgressManager.getInstance().run(new Task.Backgroundable(myWizard.getProject(), title, true, null) {
public void run(@NotNull ProgressIndicator indicator) {
createAndAlignApk(apkPath);
final CompilerManager manager = CompilerManager.getInstance(myWizard.getProject());
final CompileScope compileScope = manager.createModuleCompileScope(facet.getModule(), true);
AndroidCompileUtil.setReleaseBuild(compileScope);
manager.make(compileScope, new CompileStatusNotification() {
public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
if (aborted || errors != 0) {
return;
}
final String title = AndroidBundle.message("android.extract.package.task.title");
ProgressManager.getInstance().run(new Task.Backgroundable(myWizard.getProject(), title, true, null) {
public void run(@NotNull ProgressIndicator indicator) {
createAndAlignApk(apkPath);
}
});
}
});
}
@@ -20,17 +20,12 @@ import com.intellij.openapi.compiler.DummyCompileContext;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.xml.converters.values.BooleanValueConverter;
import org.jetbrains.android.dom.manifest.Application;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidBundle;
import javax.swing.*;
import java.awt.*;
import java.io.File;
/**
* @author Eugene.Kudelevsky
@@ -49,25 +44,24 @@ public class CheckModulePanel extends JPanel {
final DummyCompileContext compileContext = DummyCompileContext.getInstance();
VirtualFile outputDirectory = compileContext.getModuleOutputDirectory(module);
if (outputDirectory != null) {
String outputOsPath = FileUtil.toSystemDependentName(outputDirectory.getPath());
String apkFilePath = outputOsPath + File.separator + module.getName() + ".apk";
/*String apkFilePath = facet.getApkPath();
File f = new File(apkFilePath);
if (!f.isFile()) {
addError(AndroidBundle.message("android.file.not.exist.error", f.getPath()));
}
}*/
}
else {
addError(AndroidBundle.message("android.unable.to.get.output.directory.error"));
}
Manifest manifest = facet.getManifest();
/*Manifest manifest = facet.getManifest();
assert manifest != null;
Application application = manifest.getApplication();
assert application != null;
String debuggable = application.getDebuggable().getValue();
if (debuggable != null && BooleanValueConverter.getInstance(true).isTrue(debuggable)) {
addWarning(AndroidBundle.message("android.export.signed.package.debuggable.warning"));
}
}*/
}
public boolean hasError() {
@@ -18,7 +18,9 @@ package org.jetbrains.android.maven;
import com.android.sdklib.IAndroidTarget;
import com.intellij.facet.FacetType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
@@ -34,6 +36,7 @@ import org.jetbrains.android.facet.AndroidFacetConfiguration;
import org.jetbrains.android.facet.AndroidFacetType;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.sdk.AndroidSdk;
import org.jetbrains.android.sdk.AndroidSdkType;
import org.jetbrains.android.sdk.AndroidSdkUtils;
import org.jetbrains.android.sdk.EmptySdkLog;
import org.jetbrains.android.util.AndroidUtils;
@@ -55,6 +58,8 @@ import java.util.Map;
* @author Eugene.Kudelevsky
*/
public class AndroidFacetImporter extends FacetImporter<AndroidFacet, AndroidFacetConfiguration, AndroidFacetType> {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.maven.AndroidFacetImporter");
public AndroidFacetImporter() {
super("com.jayway.maven.plugins.android.generation2", "maven-android-plugin", FacetType.findInstance(AndroidFacetType.class), "Android");
}
@@ -116,6 +121,13 @@ public class AndroidFacetImporter extends FacetImporter<AndroidFacet, AndroidFac
@Nullable
private Sdk findOrCreateAndroidPlatform(MavenProject project) {
String sdkPath = System.getenv("ANDROID_HOME");
LOG.info("android home: " + sdkPath);
if (sdkPath == null) {
sdkPath = suggestAndroidSdkPath();
LOG.info("suggested sdk: " + sdkPath);
}
String apiLevel = null;
if (sdkPath != null) {
Element sdkRoot = getConfig(project, "sdk");
@@ -151,6 +163,20 @@ public class AndroidFacetImporter extends FacetImporter<AndroidFacet, AndroidFac
return null;
}
@Nullable
private static String suggestAndroidSdkPath() {
final List<Sdk> androidSdks = ProjectJdkTable.getInstance().getSdksOfType(AndroidSdkType.getInstance());
for (Sdk androidSdk : androidSdks) {
final VirtualFile sdkHome = androidSdk.getHomeDirectory();
if (sdkHome != null && sdkHome.exists() && sdkHome.isValid() && sdkHome.isDirectory()) {
return sdkHome.getPath();
}
}
return null;
}
private void configurePaths(AndroidFacet facet, MavenProject project) {
Module module = facet.getModule();
String moduleDirPath = AndroidRootUtil.getModuleDirPath(module);
@@ -27,7 +27,6 @@ import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
@@ -44,10 +43,8 @@ import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.util.PsiNavigateUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.xml.GenericAttributeValue;
import com.intellij.util.xml.converters.values.BooleanValueConverter;
import org.jdom.Element;
import org.jetbrains.android.actions.AndroidEnableDdmsAction;
import org.jetbrains.android.dom.manifest.Application;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidFacetConfiguration;
@@ -171,14 +168,14 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati
return true;
}
private static boolean containsRealDevice(@NotNull IDevice[] devices) {
/*private static boolean containsRealDevice(@NotNull IDevice[] devices) {
for (IDevice device : devices) {
if (!device.isEmulator()) {
return true;
}
}
return false;
}
}*/
public RunProfileState getState(@NotNull final Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
final Module module = getConfigurationModule().getModule();
@@ -207,11 +204,6 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati
if (!activateDdmsIfNeccessary(facet)) {
return null;
}
if (!CHOOSE_DEVICE_MANUALLY && PREFERRED_AVD.length() == 0) {
if (!checkDebuggableOption(facet)) {
return null;
}
}
}
String aPackage = getPackageName(facet);
@@ -224,11 +216,6 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati
if (CHOOSE_DEVICE_MANUALLY) {
IDevice[] devices = chooseDevicesManually(facet);
if (devices.length > 0) {
if (debug && containsRealDevice(devices)) {
if (!checkDebuggableOption(facet)) {
return null;
}
}
targetDevices = devices;
PropertiesComponent.getInstance(getProject()).setValue(ANDROID_TARGET_DEVICES_PROPERTY, toString(targetDevices));
}
@@ -249,33 +236,6 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati
return null;
}
private static boolean checkDebuggableOption(@NotNull AndroidFacet facet) {
Manifest manifest = facet.getManifest();
// validated in checkConfiguration()
assert manifest != null;
final Application application = manifest.getApplication();
if (application != null) {
String debuggable = application.getDebuggable().getValue();
BooleanValueConverter booleanValueConverter = BooleanValueConverter.getInstance(true);
if (debuggable == null || !booleanValueConverter.isTrue(debuggable)) {
Project project = facet.getModule().getProject();
int result = Messages.showYesNoCancelDialog(project, AndroidBundle.message("android.manifest.debuggable.attribute.not.true.warning"),
CommonBundle.getWarningTitle(),
Messages.getWarningIcon());
if (result == 0) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
application.getDebuggable().setValue("true");
}
});
}
return result != 2;
}
}
return true;
}
private static boolean activateDdmsIfNeccessary(@NotNull AndroidFacet facet) {
final Project project = facet.getModule().getProject();
final boolean ddmsEnabled = AndroidEnableDdmsAction.isDdmsEnabled();
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="p1.p2">
<application android:icon="@drawable/picture1">
<activity android:name=".MyA<caret>"/>
</application>
</manifest>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="p1.p2">
<application android:icon="@drawable/picture1">
<activity android:name=".MyActivity"/>
</application>
</manifest>
@@ -150,6 +150,11 @@ public class AndroidManifestDomTest extends AndroidDomTest {
doTestCompletion();
}
public void testManageSpaceActivity() throws Throwable {
copyFileToProject("MyActivity.java", "src/p1/p2/MyActivity.java");
doTestCompletion();
}
private void doTestCompletion() throws Throwable {
toTestCompletion(getTestName(false) + ".xml", getTestName(false) + "_after.xml");
}
+3 -2
View File
@@ -9,8 +9,8 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="openapi" />
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
<orderEntry type="module" module-name="testFramework-java" />
<orderEntry type="library" name="JUnit4" level="project" />
<orderEntry type="library" exported="" name="Ant" level="project" />
<orderEntry type="module" module-name="compiler-impl" />
<orderEntry type="module" module-name="java-runtime" />
@@ -23,6 +23,7 @@
<orderEntry type="module" module-name="xml-openapi" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="platform-impl" />
</component>
<component name="copyright">
<Base>
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,14 +15,15 @@
*/
package com.intellij.lang.ant;
import com.intellij.buildfiles.ForcedBuildFileAttribute;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.FileAttribute;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
@@ -31,15 +32,27 @@ import java.io.IOException;
*/
public class ForcedAntFileAttribute extends FileAttribute {
private static final Logger LOG = Logger.getInstance("#com.intellij.lang.ant.ForcedAntFileAttribute");
private static final String ANT_ID = "ant";
private static final ForcedAntFileAttribute ourAttribute = new ForcedAntFileAttribute();
private static final Key<Boolean> ourAntFileMarker = Key.create("_forced_ant_attribute_");
public ForcedAntFileAttribute() {
super("_forced_ant_attribute_", 1, true);
}
public static boolean isAntFile(VirtualFile file) {
String id = ForcedBuildFileAttribute.getFrameworkIdOfBuildFile(file);
return ANT_ID.equals(id) || (StringUtil.isEmpty(id) && isAntFileOld(file));
}
public static boolean mayBeAntFile(VirtualFile file) {
String id = ForcedBuildFileAttribute.getFrameworkIdOfBuildFile(file);
return StringUtil.isEmpty(id) || ANT_ID.equals(id);
}
private static boolean isAntFileOld(VirtualFile file) {
if (file instanceof NewVirtualFile) {
final DataInputStream is = ourAttribute.readAttribute(file);
if (is != null) {
@@ -59,24 +72,8 @@ public class ForcedAntFileAttribute extends FileAttribute {
}
return Boolean.TRUE.equals(file.getUserData(ourAntFileMarker));
}
public static void forceAntFile(VirtualFile file, boolean value) {
if (file instanceof NewVirtualFile) {
final DataOutputStream os = ourAttribute.writeAttribute(file);
try {
try {
os.writeBoolean(value);
}
finally {
os.close();
}
}
catch (IOException e) {
LOG.error(e);
}
}
else {
file.putUserData(ourAntFileMarker, Boolean.valueOf(value));
}
ForcedBuildFileAttribute.forceFileToFramework(file, ANT_ID, value);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,12 +43,13 @@ public class AntDomFileDescription extends AntFileDescription<AntDomProject> {
final XmlDocument document = xmlFile.getDocument();
if (document != null) {
final XmlTag tag = document.getRootTag();
final VirtualFile vFile = xmlFile.getOriginalFile().getVirtualFile();
if (tag != null && ROOT_TAG_NAME.equals(tag.getName()) && tag.getContext() instanceof XmlDocument) {
if (tag.getAttributeValue("name") != null && tag.getAttributeValue("default") != null) {
if (tag.getAttributeValue("name") != null && tag.getAttributeValue("default") != null
&& vFile != null && ForcedAntFileAttribute.mayBeAntFile(vFile)) {
return true;
}
}
final VirtualFile vFile = xmlFile.getOriginalFile().getVirtualFile();
if (vFile != null && ForcedAntFileAttribute.isAntFile(vFile)) {
return true;
}
@@ -232,14 +232,12 @@ public abstract class UpdatePsiFileCopyright extends AbstractUpdateCopyright {
}
}
final int pos;
if (point == null) {
pos = 0;
}
else {
int pos = 0;
if (point != null) {
final TextRange textRange = point.getTextRange();
assert textRange != null : point.getClass();
pos = textRange.getStartOffset();
if (textRange != null) {
pos = textRange.getStartOffset();
}
}
addAction(new CommentAction(pos, prefix, suffix));
}
@@ -45,14 +45,13 @@ import java.util.*;
public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthenticationNotifier.AuthenticationRequest, SVNURL> {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnAuthenticationNotifier");
private static final String ourGroupId = "SubversionId";
private final SvnVcs myVcs;
private final RootsToWorkingCopies myRootsToWorkingCopies;
private final Map<SVNURL, Boolean> myCopiesPassiveResults;
private Timer myTimer;
public SvnAuthenticationNotifier(final SvnVcs svnVcs) {
super(svnVcs.getProject(), ourGroupId, "Not Logged In to Subversion", NotificationType.ERROR);
super(svnVcs.getProject(), svnVcs.getDisplayName(), "Not Logged In to Subversion", NotificationType.ERROR);
myVcs = svnVcs;
myRootsToWorkingCopies = myVcs.getRootsToWorkingCopies();
myCopiesPassiveResults = Collections.synchronizedMap(new HashMap<SVNURL, Boolean>());
@@ -21,6 +21,8 @@ import com.intellij.ide.FrameStateListener;
import com.intellij.ide.FrameStateManager;
import com.intellij.idea.RareLogger;
import com.intellij.notification.*;
import com.intellij.notification.impl.NotificationSettings;
import com.intellij.notification.impl.NotificationsConfiguration;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
@@ -221,6 +223,24 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
myFrameStateListener = new MyFrameStateListener(changeListManager, vcsDirtyScopeManager);
myWorkingCopiesContent = new WorkingCopiesContent(this);
// remove used some time before old notification group ids
correctNotificationIds();
}
private void correctNotificationIds() {
boolean notEmpty = NotificationsConfiguration.getSettings("SVN_NO_JNA") != null ||
NotificationsConfiguration.getSettings("SVN_NO_CRYPT32") != null ||
NotificationsConfiguration.getSettings("SubversionId") != null;
if (notEmpty) {
NotificationsConfiguration.remove(new NotificationSettings[] {new NotificationSettings("SVN_NO_JNA", null),
new NotificationSettings("SVN_NO_CRYPT32", null), new NotificationSettings("SubversionId", null)});
// if group ids is being changed, set highest level first
final NotificationSettings settings = NotificationsConfiguration.getSettings(getDisplayName());
if (settings != null) {
settings.setDisplayType(NotificationDisplayType.STICKY_BALLOON);
}
}
}
public void postStartup() {
@@ -328,15 +348,13 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
}
}
private final static String UPGRADE_SUBVERSION_FORMAT = "Subversion";
private void upgradeToRecentVersion(final SvnConfiguration.SvnSupportOptions supportOptions) {
if (! supportOptions.upgradeTo16Asked()) {
final SvnWorkingCopyChecker workingCopyChecker = new SvnWorkingCopyChecker();
if (workingCopyChecker.upgradeNeeded()) {
Notifications.Bus.notify(new Notification(UPGRADE_SUBVERSION_FORMAT, SvnBundle.message("upgrade.format.to16.question.title"),
Notifications.Bus.notify(new Notification(getDisplayName(), SvnBundle.message("upgrade.format.to16.question.title"),
"Old format Subversion working copies <a href=\"\">could be upgraded to version 1.6</a>.",
NotificationType.INFORMATION, new NotificationListener() {
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
@@ -374,10 +392,10 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
if (SystemInfo.isWindows) {
if (! SVNJNAUtil.isJNAPresent()) {
Notifications.Bus.notify(new Notification("SVN_NO_JNA", "Subversion plugin: no JNA",
Notifications.Bus.notify(new Notification(getDisplayName(), "Subversion plugin: no JNA",
"A problem with JNA initialization for svnkit library. Encryption is not available.", NotificationType.WARNING), NotificationDisplayType.BALLOON, myProject);
} else if (! SVNJNAUtil.isWinCryptEnabled()) {
Notifications.Bus.notify(new Notification("SVN_NO_CRYPT32", "Subversion plugin: no encryption",
Notifications.Bus.notify(new Notification(getDisplayName(), "Subversion plugin: no encryption",
"A problem with encryption module (Crypt32.dll) initialization for svnkit library. Encryption is not available.", NotificationType.WARNING), NotificationDisplayType.BALLOON, myProject);
}
}