mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git@git.labs.intellij.net:idea/community
This commit is contained in:
@@ -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());
|
||||
|
||||
+3
-1
@@ -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();
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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() {
|
||||
|
||||
+5
@@ -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));
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-1
@@ -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();
|
||||
}
|
||||
|
||||
+21
-4
@@ -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();
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+8
-8
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+16
@@ -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());
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -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.
|
||||
|
||||
+37
-59
@@ -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;
|
||||
}
|
||||
|
||||
+38
-53
@@ -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,
|
||||
|
||||
+374
@@ -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;
|
||||
}
|
||||
}
|
||||
+9
@@ -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>
|
||||
+15
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+29
@@ -42,4 +42,33 @@
|
||||
<description>Contents of array <code>foo</code> 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 <code>barzoom</code> 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 <code>arr</code> 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 <code>barzoom</code> 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 <code>rowData</code> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+111
-8
@@ -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;
|
||||
|
||||
+6
-2
@@ -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) {
|
||||
|
||||
+10
-3
@@ -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)
|
||||
|
||||
+3
-1
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+4
-10
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user