mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 09:03:31 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -154,23 +154,25 @@ public class CompileDriver {
|
||||
|
||||
myGenerationCompilerModuleToOutputDirMap = new HashMap<Pair<IntermediateOutputCompiler, Module>, Pair<VirtualFile, VirtualFile>>();
|
||||
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
final IntermediateOutputCompiler[] generatingCompilers = CompilerManager.getInstance(myProject).getCompilers(IntermediateOutputCompiler.class, myCompilerFilter);
|
||||
final Module[] allModules = ModuleManager.getInstance(myProject).getModules();
|
||||
final CompilerConfiguration config = CompilerConfiguration.getInstance(project);
|
||||
for (Module module : allModules) {
|
||||
for (IntermediateOutputCompiler compiler : generatingCompilers) {
|
||||
final VirtualFile productionOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, false));
|
||||
final VirtualFile testOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, true));
|
||||
final Pair<IntermediateOutputCompiler, Module> pair = new Pair<IntermediateOutputCompiler, Module>(compiler, module);
|
||||
final Pair<VirtualFile, VirtualFile> outputs = new Pair<VirtualFile, VirtualFile>(productionOutput, testOutput);
|
||||
myGenerationCompilerModuleToOutputDirMap.put(pair, outputs);
|
||||
}
|
||||
if (config.isAnnotationProcessorsEnabled()) {
|
||||
if (config.isAnnotationProcessingEnabled(module)) {
|
||||
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
|
||||
if (path != null) {
|
||||
lookupVFile(lfs, path); // ensure the file is created and added to VFS
|
||||
if (!useCompileServer()) {
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
final IntermediateOutputCompiler[] generatingCompilers = CompilerManager.getInstance(myProject).getCompilers(IntermediateOutputCompiler.class, myCompilerFilter);
|
||||
final Module[] allModules = ModuleManager.getInstance(myProject).getModules();
|
||||
final CompilerConfiguration config = CompilerConfiguration.getInstance(project);
|
||||
for (Module module : allModules) {
|
||||
for (IntermediateOutputCompiler compiler : generatingCompilers) {
|
||||
final VirtualFile productionOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, false));
|
||||
final VirtualFile testOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, true));
|
||||
final Pair<IntermediateOutputCompiler, Module> pair = new Pair<IntermediateOutputCompiler, Module>(compiler, module);
|
||||
final Pair<VirtualFile, VirtualFile> outputs = new Pair<VirtualFile, VirtualFile>(productionOutput, testOutput);
|
||||
myGenerationCompilerModuleToOutputDirMap.put(pair, outputs);
|
||||
}
|
||||
if (config.isAnnotationProcessorsEnabled()) {
|
||||
if (config.isAnnotationProcessingEnabled(module)) {
|
||||
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
|
||||
if (path != null) {
|
||||
lookupVFile(lfs, path); // ensure the file is created and added to VFS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +55,11 @@ public class PaletteWindow extends JPanel implements DataProvider {
|
||||
private PaletteGroupHeader myLastFocusedGroup;
|
||||
|
||||
@NonNls private static final String ourHelpID = "guiDesigner.uiTour.palette";
|
||||
private PaletteManager myPaletteManager;
|
||||
|
||||
public PaletteWindow(Project project) {
|
||||
myProject = project;
|
||||
myPaletteManager = PaletteManager.getInstance(myProject);
|
||||
myProviders = Extensions.getExtensions(PaletteItemProvider.EP_NAME, project);
|
||||
for(PaletteItemProvider provider: myProviders) {
|
||||
provider.addListener(myPropertyChangeListener);
|
||||
@@ -180,7 +182,7 @@ public class PaletteWindow extends JPanel implements DataProvider {
|
||||
group.getComponentList().clearSelection();
|
||||
}
|
||||
ListSelectionEvent event = new ListSelectionEvent(this, -1, -1, false);
|
||||
PaletteManager.getInstance(myProject).notifySelectionChanged(event);
|
||||
myPaletteManager.notifySelectionChanged(event);
|
||||
}
|
||||
|
||||
@Nullable public PaletteItem getActiveItem() {
|
||||
@@ -252,7 +254,7 @@ public class PaletteWindow extends JPanel implements DataProvider {
|
||||
break;
|
||||
}
|
||||
}
|
||||
PaletteManager.getInstance(myProject).notifySelectionChanged(e);
|
||||
myPaletteManager.notifySelectionChanged(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -53,8 +53,7 @@ class ProjectStructureElementRenderer extends ColoredTreeCellRenderer {
|
||||
setToolTipText(null);
|
||||
setFont(UIUtil.getTreeFont());
|
||||
|
||||
SimpleTextAttributes textAttributes =
|
||||
selected && hasFocus ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES;
|
||||
SimpleTextAttributes textAttributes = SimpleTextAttributes.REGULAR_ATTRIBUTES;
|
||||
if (node.isDisplayInBold()) {
|
||||
textAttributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES;
|
||||
}
|
||||
@@ -74,6 +73,13 @@ class ProjectStructureElementRenderer extends ColoredTreeCellRenderer {
|
||||
textAttributes = textAttributes.derive(style, foreground, null, waveColor);
|
||||
setToolTipText(problemsHolder.composeTooltipMessage());
|
||||
}
|
||||
|
||||
append(displayName, textAttributes);
|
||||
String description = projectStructureElement.getDescription();
|
||||
if (description != null) {
|
||||
append(" (" + description + ")", SimpleTextAttributes.GRAY_ATTRIBUTES, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
append(displayName, textAttributes);
|
||||
|
||||
+5
@@ -18,6 +18,11 @@ public abstract class ProjectStructureElement {
|
||||
|
||||
public abstract String getPresentableName();
|
||||
|
||||
@Nullable
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract String getTypeName();
|
||||
|
||||
public abstract String getId();
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package com.intellij.util.descriptors.impl;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.MultiValuesMap;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.descriptors.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -135,6 +136,7 @@ public class ConfigFileContainerImpl implements ConfigFileContainer {
|
||||
}
|
||||
for (ConfigFileInfo configuration : newDescriptors) {
|
||||
final ConfigFileImpl configFile = new ConfigFileImpl(this, configuration);
|
||||
Disposer.register(this, configFile);
|
||||
myConfigFiles.put(metaData, configFile);
|
||||
added.add(configFile);
|
||||
}
|
||||
@@ -142,6 +144,7 @@ public class ConfigFileContainerImpl implements ConfigFileContainer {
|
||||
|
||||
for (ConfigFile descriptor : toDelete) {
|
||||
myConfigFiles.remove(descriptor.getMetaData(), descriptor);
|
||||
Disposer.dispose(descriptor);
|
||||
}
|
||||
|
||||
myCachedConfigFiles = null;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
package com.intellij.util.descriptors.impl;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -22,43 +21,38 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public class ConfigFileImpl implements ConfigFile {
|
||||
@NotNull private ConfigFileInfo myInfo;
|
||||
private VirtualFilePointer myFilePointer;
|
||||
private PsiFile myPsiFile;
|
||||
private final VirtualFilePointer myFilePointer;
|
||||
private volatile PsiFile myPsiFile;
|
||||
private final ConfigFileContainerImpl myContainer;
|
||||
private final Project myProject;
|
||||
private long myModificationCount;
|
||||
private final Object myPsiFileLock = new Object();
|
||||
private final VirtualFilePointerListener myListener = new VirtualFilePointerListener() {
|
||||
public void beforeValidityChanged(final VirtualFilePointer[] pointers) {
|
||||
}
|
||||
|
||||
public void validityChanged(final VirtualFilePointer[] pointers) {
|
||||
synchronized (myPsiFileLock) {
|
||||
myPsiFile = null;
|
||||
}
|
||||
onChange();
|
||||
}
|
||||
};
|
||||
|
||||
public ConfigFileImpl(@NotNull final ConfigFileContainerImpl container, @NotNull final ConfigFileInfo configuration) {
|
||||
myContainer = container;
|
||||
myInfo = configuration;
|
||||
setUrl(configuration.getUrl());
|
||||
final VirtualFilePointerManager pointerManager = VirtualFilePointerManager.getInstance();
|
||||
myFilePointer = pointerManager.create(configuration.getUrl(), this, new VirtualFilePointerListener() {
|
||||
@Override
|
||||
public void beforeValidityChanged(final VirtualFilePointer[] pointers) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validityChanged(final VirtualFilePointer[] pointers) {
|
||||
myPsiFile = null;
|
||||
onChange();
|
||||
}
|
||||
});
|
||||
onChange();
|
||||
Disposer.register(container, this);
|
||||
myProject = myContainer.getProject();
|
||||
}
|
||||
|
||||
private void setUrl(String url) {
|
||||
final VirtualFilePointerManager pointerManager = VirtualFilePointerManager.getInstance();
|
||||
myFilePointer = pointerManager.create(url, this, myListener);
|
||||
onChange();
|
||||
}
|
||||
|
||||
private void onChange() {
|
||||
myModificationCount++;
|
||||
myContainer.fireDescriptorChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return myFilePointer.getUrl();
|
||||
}
|
||||
@@ -67,17 +61,16 @@ public class ConfigFileImpl implements ConfigFile {
|
||||
myInfo = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VirtualFile getVirtualFile() {
|
||||
return myFilePointer.getFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiFile getPsiFile() {
|
||||
PsiFile psiFile;
|
||||
synchronized (myPsiFileLock) {
|
||||
psiFile = myPsiFile;
|
||||
}
|
||||
PsiFile psiFile = myPsiFile;
|
||||
|
||||
if (psiFile != null && psiFile.isValid()) {
|
||||
return psiFile;
|
||||
@@ -88,27 +81,29 @@ public class ConfigFileImpl implements ConfigFile {
|
||||
|
||||
psiFile = PsiManager.getInstance(myProject).findFile(virtualFile);
|
||||
|
||||
synchronized (myPsiFileLock) {
|
||||
myPsiFile = psiFile;
|
||||
}
|
||||
myPsiFile = psiFile;
|
||||
|
||||
return psiFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public XmlFile getXmlFile() {
|
||||
final PsiFile file = getPsiFile();
|
||||
return file instanceof XmlFile ? (XmlFile)file : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ConfigFileInfo getInfo() {
|
||||
return myInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
final PsiFile psiFile = getPsiFile();
|
||||
if (psiFile == null || !psiFile.isValid()) {
|
||||
@@ -122,12 +117,14 @@ public class ConfigFileImpl implements ConfigFile {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ConfigFileMetaData getMetaData() {
|
||||
return myInfo.getMetaData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getModificationCount() {
|
||||
return myModificationCount;
|
||||
}
|
||||
|
||||
@@ -112,9 +112,11 @@ public class JavaNoVariantsDelegator extends CompletionContributor {
|
||||
PsiType type = JavaCompletionUtil.getLookupElementType(base);
|
||||
if (type != null && !PsiType.VOID.equals(type)) {
|
||||
PsiReferenceExpression ref = ReferenceExpressionCompletionContributor.createMockReference(position, type, base);
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters,
|
||||
result.getPrefixMatcher())) {
|
||||
qualifiedCollector.addElement(new JavaChainLookupElement(base, item));
|
||||
if (ref != null) {
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters,
|
||||
result.getPrefixMatcher())) {
|
||||
qualifiedCollector.addElement(new JavaChainLookupElement(base, item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-10
@@ -25,8 +25,8 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.PsiJavaPatterns;
|
||||
import com.intellij.patterns.PsiMethodPattern;
|
||||
import com.intellij.patterns.StandardPatterns;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
@@ -46,7 +46,10 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiMethod;
|
||||
@@ -57,7 +60,7 @@ import static com.intellij.patterns.PsiJavaPatterns.psiMethod;
|
||||
public class ReferenceExpressionCompletionContributor {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor");
|
||||
private static final PsiMethodPattern OBJECT_METHOD_PATTERN = psiMethod().withName(
|
||||
PsiJavaPatterns.string().oneOf("hashCode", "equals", "finalize", "wait", "notify", "notifyAll", "getClass", "clone", "toString")).
|
||||
StandardPatterns.string().oneOf("hashCode", "equals", "finalize", "wait", "notify", "notifyAll", "getClass", "clone", "toString")).
|
||||
definedInClass(CommonClassNames.JAVA_LANG_OBJECT);
|
||||
private static final PrefixMatcher TRUE_MATCHER = new PrefixMatcher("") {
|
||||
@Override
|
||||
@@ -83,9 +86,9 @@ public class ReferenceExpressionCompletionContributor {
|
||||
}
|
||||
|
||||
if (psiElement().inside(
|
||||
PsiJavaPatterns.or(
|
||||
psiElement(PsiAnnotationParameterList.class),
|
||||
psiElement(PsiSwitchLabelStatement.class))
|
||||
StandardPatterns.or(
|
||||
psiElement(PsiAnnotationParameterList.class),
|
||||
psiElement(PsiSwitchLabelStatement.class))
|
||||
).accepts(element)) {
|
||||
return new ElementExtractorFilter(new AndFilter(
|
||||
new ClassFilter(PsiField.class),
|
||||
@@ -426,27 +429,37 @@ public class ReferenceExpressionCompletionContributor {
|
||||
PsiType qualifierType,
|
||||
final PsiType expectedType, JavaSmartCompletionParameters parameters) throws IncorrectOperationException {
|
||||
final PsiReferenceExpression mockRef = createMockReference(place, qualifierType, qualifierItem);
|
||||
if (mockRef == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ElementFilter filter = getReferenceFilter(place, true);
|
||||
for (final LookupElement item : completeFinalReference(place, mockRef, filter, parameters)) {
|
||||
if (shoudChain(place, qualifierType, expectedType, item)) {
|
||||
if (shouldChain(place, qualifierType, expectedType, item)) {
|
||||
result.consume(new JavaChainLookupElement(qualifierItem, item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiReferenceExpression createMockReference(final PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(place.getProject());
|
||||
if (qualifierItem.getObject() instanceof PsiClass) {
|
||||
return (PsiReferenceExpression)factory
|
||||
.createExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place);
|
||||
try {
|
||||
return (PsiReferenceExpression)factory
|
||||
.createExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", JavaCompletionUtil
|
||||
.createContextWithXxxVariable(place, qualifierType));
|
||||
}
|
||||
|
||||
private static boolean shoudChain(PsiElement element, PsiType qualifierType, PsiType expectedType, LookupElement item) {
|
||||
private static boolean shouldChain(PsiElement element, PsiType qualifierType, PsiType expectedType, LookupElement item) {
|
||||
if (item.getObject() instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)item.getObject();
|
||||
if (psiMethod().withName("toArray").withParameterCount(1)
|
||||
|
||||
@@ -272,7 +272,7 @@ public class PsiImplUtil {
|
||||
return new PsiImmediateClassType(classClass, substitutor);
|
||||
}
|
||||
|
||||
public static PsiAnnotation findAnnotation(@NotNull PsiAnnotationOwner modifierList, @NotNull String qualifiedName) {
|
||||
@Nullable public static PsiAnnotation findAnnotation(@NotNull PsiAnnotationOwner modifierList, @NotNull String qualifiedName) {
|
||||
final String shortName = StringUtil.getShortName(qualifiedName);
|
||||
PsiAnnotation[] annotations = modifierList.getAnnotations();
|
||||
for (PsiAnnotation annotation : annotations) {
|
||||
@@ -368,7 +368,7 @@ public class PsiImplUtil {
|
||||
}
|
||||
else if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
PsiClass topClass = PsiUtil.getTopLevelClass(member);
|
||||
return topClass != null ? new LocalSearchScope(topClass) : new LocalSearchScope(file);
|
||||
return topClass != null ? new LocalSearchScope(topClass) : file != null ? new LocalSearchScope(file) : maximalUseScope;
|
||||
}
|
||||
else {
|
||||
if (file instanceof PsiJavaFile) {
|
||||
@@ -388,7 +388,7 @@ public class PsiImplUtil {
|
||||
return getServerPageFile(element) != null;
|
||||
}
|
||||
|
||||
public static ServerPageFile getServerPageFile(final PsiElement element) {
|
||||
@Nullable public static ServerPageFile getServerPageFile(final PsiElement element) {
|
||||
final PsiFile psiFile = PsiUtilCore.getTemplateLanguageFile(element);
|
||||
return psiFile instanceof ServerPageFile ? (ServerPageFile)psiFile : null;
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ public class PsiScopesUtil {
|
||||
|
||||
public static boolean resolveAndWalk(PsiScopeProcessor processor,
|
||||
PsiJavaCodeReferenceElement ref,
|
||||
PsiElement maxScope,
|
||||
@Nullable PsiElement maxScope,
|
||||
boolean incompleteCode) {
|
||||
final PsiElement qualifier = ref.getQualifier();
|
||||
final PsiElement classNameElement = ref.getReferenceNameElement();
|
||||
|
||||
@@ -109,7 +109,6 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).cleanupForNextTest();
|
||||
|
||||
final LocalInspectionTool[] tools = configureLocalInspectionTools();
|
||||
for (LocalInspectionTool tool : tools) {
|
||||
|
||||
@@ -77,8 +77,9 @@ public abstract class ModuleLevelBuilder extends Builder {
|
||||
|
||||
final HashSet<File> affectedBeforeDif = new HashSet<File>(allAffectedFiles);
|
||||
|
||||
final ModulesBasedFileFilter moduleBasedFilter = new ModulesBasedFileFilter(context, chunk);
|
||||
final boolean incremental = globalMappings.differentiate(
|
||||
delta, removedPaths, filesToCompile, allCompiledFiles, allAffectedFiles
|
||||
delta, removedPaths, filesToCompile, allCompiledFiles, allAffectedFiles, moduleBasedFilter
|
||||
);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
@@ -103,13 +104,13 @@ public abstract class ModuleLevelBuilder extends Builder {
|
||||
|
||||
if (!newlyAffectedFiles.isEmpty()) {
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
final List<Pair<File, Module>> wrongFiles = checkAffectedFilesInCorrectModules(context, chunk, newlyAffectedFiles);
|
||||
final List<Pair<File, Module>> wrongFiles = checkAffectedFilesInCorrectModules(context, newlyAffectedFiles, moduleBasedFilter);
|
||||
if (!wrongFiles.isEmpty()) {
|
||||
LOG.debug("Wrong affected files for module chunk " + chunk.getName() + ": ");
|
||||
for (Pair<File, Module> pair : wrongFiles) {
|
||||
LOG.debug("\t[" + pair.second.getName() + "] " + pair.first.getPath());
|
||||
final String name = pair.second != null? pair.second.getName() : "null";
|
||||
LOG.debug("\t[" + name + "] " + pair.first.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,45 +147,20 @@ public abstract class ModuleLevelBuilder extends Builder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static List<Pair<File, Module>> checkAffectedFilesInCorrectModules(CompileContext context, ModuleChunk currentChunk, Collection<File> affected) {
|
||||
private static List<Pair<File, Module>> checkAffectedFilesInCorrectModules(CompileContext context, Collection<File> affected, ModulesBasedFileFilter moduleBasedFilter) {
|
||||
if (affected.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Set<Module> chunkModules = currentChunk.getModules();
|
||||
final Map<Module, Set<Module>> cache = new HashMap<Module, Set<Module>>();
|
||||
final List<Pair<File, Module>> result = new ArrayList<Pair<File, Module>>();
|
||||
|
||||
for (File file : affected) {
|
||||
final RootDescriptor moduleAndRoot = context.getModuleAndRoot(file);
|
||||
if (moduleAndRoot == null) {
|
||||
continue;
|
||||
if (!moduleBasedFilter.accept(file)) {
|
||||
final RootDescriptor moduleAndRoot = context.getModuleAndRoot(file);
|
||||
result.add(Pair.create(file, moduleAndRoot != null? moduleAndRoot.module : null));
|
||||
}
|
||||
final Module moduleOfFile = moduleAndRoot.module;
|
||||
if (chunkModules.contains(moduleOfFile)) {
|
||||
continue;
|
||||
}
|
||||
Set<Module> moduleOfFileWithDependencies = cache.get(moduleOfFile);
|
||||
if (moduleOfFileWithDependencies == null) {
|
||||
moduleOfFileWithDependencies = ProjectPaths.getModulesWithDependentsRecursively(moduleOfFile, true);
|
||||
cache.put(moduleOfFile, moduleOfFileWithDependencies);
|
||||
}
|
||||
if (intersects(moduleOfFileWithDependencies, chunkModules)) {
|
||||
continue;
|
||||
}
|
||||
result.add(Pair.create(file, moduleOfFile));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean intersects(Set<Module> set1, Set<Module> set2) {
|
||||
if (set1.size() < set2.size()) {
|
||||
return new HashSet<Module>(set1).removeAll(set2);
|
||||
}
|
||||
return new HashSet<Module>(set2).removeAll(set1);
|
||||
}
|
||||
|
||||
private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set<File> affected) throws IOException {
|
||||
final Set<Module> chunkModules = new HashSet<Module>(chunk.getModules());
|
||||
if (!chunkModules.isEmpty()) {
|
||||
@@ -221,4 +197,40 @@ public abstract class ModuleLevelBuilder extends Builder {
|
||||
return removed != null? removed : Collections.<String>emptySet();
|
||||
}
|
||||
|
||||
private static class ModulesBasedFileFilter implements Mappings.DependentFilesFilter{
|
||||
private final CompileContext myContext;
|
||||
private final Set<Module> myChunkModules;
|
||||
private final Map<Module, Set<Module>> myCache = new HashMap<Module, Set<Module>>();
|
||||
|
||||
private ModulesBasedFileFilter(CompileContext context, ModuleChunk chunk) {
|
||||
myContext = context;
|
||||
myChunkModules = chunk.getModules();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
final RootDescriptor moduleAndRoot = myContext.getModuleAndRoot(file);
|
||||
if (moduleAndRoot == null) {
|
||||
return true;
|
||||
}
|
||||
final Module moduleOfFile = moduleAndRoot.module;
|
||||
if (myChunkModules.contains(moduleOfFile)) {
|
||||
return true;
|
||||
}
|
||||
Set<Module> moduleOfFileWithDependencies = myCache.get(moduleOfFile);
|
||||
if (moduleOfFileWithDependencies == null) {
|
||||
moduleOfFileWithDependencies = ProjectPaths.getModulesWithDependentsRecursively(moduleOfFile, true);
|
||||
myCache.put(moduleOfFile, moduleOfFileWithDependencies);
|
||||
}
|
||||
return intersects(moduleOfFileWithDependencies, myChunkModules);
|
||||
}
|
||||
|
||||
private static boolean intersects(Set<Module> set1, Set<Module> set2) {
|
||||
if (set1.size() < set2.size()) {
|
||||
return new HashSet<Module>(set1).removeAll(set2);
|
||||
}
|
||||
return new HashSet<Module>(set2).removeAll(set1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -806,7 +806,10 @@ public class Mappings {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean incrementalDecision(final DependencyContext.S owner, final Proto member, final Collection<File> affectedFiles) {
|
||||
private boolean incrementalDecision(final DependencyContext.S owner,
|
||||
final Proto member,
|
||||
final Collection<File> affectedFiles,
|
||||
DependentFilesFilter filter) {
|
||||
final boolean isField = member instanceof FieldRepr;
|
||||
final Util self = new Util(this);
|
||||
|
||||
@@ -842,19 +845,33 @@ public class Mappings {
|
||||
|
||||
if (ClassRepr.getPackageName(myContext.getValue(className)).equals(packageName)) {
|
||||
final String f = myContext.getValue(fileName);
|
||||
debug("Adding: ", f);
|
||||
affectedFiles.add(new File(f));
|
||||
final File file = new File(f);
|
||||
if (filter.accept(file)) {
|
||||
debug("Adding: ", f);
|
||||
affectedFiles.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public interface DependentFilesFilter {
|
||||
DependentFilesFilter ALL_FILES = new DependentFilesFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
boolean accept(File file);
|
||||
}
|
||||
|
||||
public boolean differentiate(final Mappings delta,
|
||||
final Collection<String> removed,
|
||||
final Collection<File> filesToCompile,
|
||||
final Collection<File> compiledFiles,
|
||||
final Collection<File> affectedFiles) {
|
||||
final Collection<File> affectedFiles, DependentFilesFilter filter) {
|
||||
synchronized (myLock) {
|
||||
debug("Begin of Differentiate:");
|
||||
|
||||
@@ -926,7 +943,7 @@ public class Mappings {
|
||||
|
||||
if (it.isAnnotation() && it.policy == RetentionPolicy.SOURCE) {
|
||||
debug("Annotation, retention policy = SOURCE => a switch to non-incremental mode requested");
|
||||
if (!incrementalDecision(it.outerClassName, it, affectedFiles)) {
|
||||
if (!incrementalDecision(it.outerClassName, it, affectedFiles, filter)) {
|
||||
debug("End of Differentiate, returning false");
|
||||
return false;
|
||||
}
|
||||
@@ -970,7 +987,7 @@ public class Mappings {
|
||||
|
||||
if (removedtargets.contains(ElementType.LOCAL_VARIABLE)) {
|
||||
debug("Removed target contains LOCAL_VARIABLE => a switch to non-incremental mode requested");
|
||||
if (!incrementalDecision(it.outerClassName, it, affectedFiles)) {
|
||||
if (!incrementalDecision(it.outerClassName, it, affectedFiles, filter)) {
|
||||
debug("End of Differentiate, returning false");
|
||||
return false;
|
||||
}
|
||||
@@ -1396,7 +1413,7 @@ public class Mappings {
|
||||
|
||||
if ((f.access & Opcodes.ACC_PRIVATE) == 0 && (f.access & mask) == mask && f.hasValue()) {
|
||||
debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested");
|
||||
if (!incrementalDecision(it.name, f, affectedFiles)) {
|
||||
if (!incrementalDecision(it.name, f, affectedFiles, filter)) {
|
||||
debug("End of Differentiate, returning false");
|
||||
return false;
|
||||
}
|
||||
@@ -1417,7 +1434,7 @@ public class Mappings {
|
||||
if ((field.access & Opcodes.ACC_PRIVATE) == 0 && (field.access & mask) == mask) {
|
||||
if ((d.base() & Difference.ACCESS) > 0 || (d.base() & Difference.VALUE) > 0) {
|
||||
debug("Inline field changed it's access or value => a switch to non-incremental mode requested");
|
||||
if (!incrementalDecision(it.name, field, affectedFiles)) {
|
||||
if (!incrementalDecision(it.name, field, affectedFiles, filter)) {
|
||||
debug("End of Differentiate, returning false");
|
||||
return false;
|
||||
}
|
||||
@@ -1633,40 +1650,46 @@ public class Mappings {
|
||||
|
||||
if (delta.isDifferentiated()) {
|
||||
for (DependencyContext.S c : delta.getChangedClasses()) {
|
||||
myClassToSubclasses.remove(c);
|
||||
|
||||
final Collection<DependencyContext.S> subClasses = delta.myClassToSubclasses.get(c);
|
||||
|
||||
if (subClasses != null) {
|
||||
myClassToSubclasses.put(c, subClasses);
|
||||
myClassToSubclasses.replace(c, subClasses);
|
||||
}
|
||||
else {
|
||||
myClassToSubclasses.remove(c);
|
||||
}
|
||||
|
||||
myClassToSourceFile.remove(c);
|
||||
|
||||
final DependencyContext.S sourceFile = delta.myClassToSourceFile.get(c);
|
||||
|
||||
if (sourceFile != null) {
|
||||
myClassToSourceFile.put(c, sourceFile);
|
||||
}
|
||||
else {
|
||||
myClassToSourceFile.remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
for (DependencyContext.S f : delta.getChangedFiles()) {
|
||||
mySourceFileToClasses.remove(f);
|
||||
final Collection<ClassRepr> classes = delta.mySourceFileToClasses.get(f);
|
||||
if (classes != null) {
|
||||
mySourceFileToClasses.put(f, classes);
|
||||
mySourceFileToClasses.replace(f, classes);
|
||||
}
|
||||
else {
|
||||
mySourceFileToClasses.remove(f);
|
||||
}
|
||||
|
||||
mySourceFileToUsages.remove(f);
|
||||
final Collection<UsageRepr.Cluster> clusters = delta.mySourceFileToUsages.get(f);
|
||||
if (clusters != null) {
|
||||
mySourceFileToUsages.put(f, clusters);
|
||||
mySourceFileToUsages.replace(f, clusters);
|
||||
}
|
||||
else {
|
||||
mySourceFileToUsages.remove(f);
|
||||
}
|
||||
|
||||
mySourceFileToAnnotationUsages.remove(f);
|
||||
final Collection<UsageRepr.Usage> usages = delta.mySourceFileToAnnotationUsages.get(f);
|
||||
if (usages != null) {
|
||||
mySourceFileToAnnotationUsages.put(f, usages);
|
||||
mySourceFileToAnnotationUsages.replace(f, usages);
|
||||
}
|
||||
else {
|
||||
mySourceFileToAnnotationUsages.remove(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1711,8 +1734,7 @@ public class Mappings {
|
||||
changed |= past.addAll(now);
|
||||
|
||||
if (changed) {
|
||||
myClassToClassDependency.remove(aClass);
|
||||
myClassToClassDependency.put(aClass, past);
|
||||
myClassToClassDependency.replace(aClass, past);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ interface MultiMaplet<K, V> {
|
||||
Collection<V> get(final K key);
|
||||
void put(final K key, final V value);
|
||||
void put(final K key, final Collection<V> value);
|
||||
void replace(final K key, final Collection<V> value);
|
||||
void putAll(MultiMaplet<K,V> m);
|
||||
void replaceAll(MultiMaplet<K, V> m);
|
||||
void remove(final K key);
|
||||
|
||||
@@ -66,6 +66,21 @@ class PersistentMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replace(K key, Collection<V> value) {
|
||||
try {
|
||||
if (value == null) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
else {
|
||||
myMap.put(key, value);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final K key, final Collection<V> value) {
|
||||
try {
|
||||
@@ -149,9 +164,7 @@ class PersistentMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
@Override
|
||||
public void replaceAll(MultiMaplet<K, V> m) {
|
||||
for (Map.Entry<K, Collection<V>> entry : m.entrySet()) {
|
||||
final K key = entry.getKey();
|
||||
remove(key);
|
||||
put(key, entry.getValue());
|
||||
replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,16 @@ class TransientMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replace(K key, Collection<V> value) {
|
||||
if (value == null) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
else {
|
||||
myMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final K key, final V value) {
|
||||
final Collection<V> x = constr.create();
|
||||
@@ -111,8 +121,7 @@ class TransientMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
@Override
|
||||
public void replaceAll(MultiMaplet<K, V> m) {
|
||||
for (Map.Entry<K, Collection<V>> e : m.entrySet()) {
|
||||
remove(e.getKey());
|
||||
put(e.getKey(), e.getValue());
|
||||
replace(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1163,7 +1163,8 @@ public class ProjectWrapper {
|
||||
|
||||
final Collection<File> affected = new HashSet<File>();
|
||||
|
||||
final boolean incremental = dependencyMapping.differentiate(delta, removed, files, compiled, affected);
|
||||
final boolean incremental = dependencyMapping.differentiate(delta, removed, files, compiled, affected,
|
||||
Mappings.DependentFilesFilter.ALL_FILES);
|
||||
|
||||
for (File a : affected) {
|
||||
affectedFiles.add(FileUtil.toSystemIndependentName(a.getAbsolutePath()));
|
||||
|
||||
@@ -269,7 +269,7 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* @return the element which was actually added (either <code>element</code> or its copy).
|
||||
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
|
||||
*/
|
||||
PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException;
|
||||
PsiElement addBefore(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException;
|
||||
|
||||
/**
|
||||
* Adds a child to this PSI element, after the specified anchor element.
|
||||
@@ -279,7 +279,7 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* @return the element which was actually added (either <code>element</code> or its copy).
|
||||
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
|
||||
*/
|
||||
PsiElement addAfter(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException;
|
||||
PsiElement addAfter(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException;
|
||||
|
||||
/**
|
||||
* Checks if it is possible to add the specified element as a child to this element,
|
||||
|
||||
@@ -41,11 +41,11 @@ public class LocalSearchScope extends SearchScope {
|
||||
public static final LocalSearchScope EMPTY = new LocalSearchScope(PsiElement.EMPTY_ARRAY);
|
||||
private String myDisplayName;
|
||||
|
||||
public LocalSearchScope(PsiElement scope) {
|
||||
public LocalSearchScope(@NotNull PsiElement scope) {
|
||||
this(scope, null);
|
||||
}
|
||||
|
||||
public LocalSearchScope(PsiElement scope, String displayName) {
|
||||
public LocalSearchScope(@NotNull PsiElement scope, @Nullable String displayName) {
|
||||
this(new PsiElement[]{scope});
|
||||
myDisplayName = displayName;
|
||||
}
|
||||
@@ -54,16 +54,17 @@ public class LocalSearchScope extends SearchScope {
|
||||
this(scope, null);
|
||||
}
|
||||
|
||||
public LocalSearchScope(PsiElement[] scope, String displayName) {
|
||||
public LocalSearchScope(PsiElement[] scope, @Nullable String displayName) {
|
||||
this(scope, displayName, false);
|
||||
}
|
||||
|
||||
public LocalSearchScope(final PsiElement[] scope, final String displayName, final boolean ignoreInjectedPsi) {
|
||||
public LocalSearchScope(final PsiElement[] scope, @Nullable final String displayName, final boolean ignoreInjectedPsi) {
|
||||
myIgnoreInjectedPsi = ignoreInjectedPsi;
|
||||
myDisplayName = displayName;
|
||||
Set<PsiElement> localScope = new LinkedHashSet<PsiElement>(scope.length);
|
||||
|
||||
for (final PsiElement element : scope) {
|
||||
LOG.assertTrue(element != null, "null element");
|
||||
LOG.assertTrue(element.getContainingFile() != null, element.getClass().getName());
|
||||
if (element instanceof PsiFile) {
|
||||
List<PsiFile> files = ((PsiFile)element).getViewProvider().getAllFiles();
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import com.intellij.util.messages.Topic;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface DocumentBulkUpdateListener {
|
||||
Topic<DocumentBulkUpdateListener> TOPIC = Topic.create("Bulk document change notifcation like reformat, etc.", DocumentBulkUpdateListener.class);
|
||||
Topic<DocumentBulkUpdateListener> TOPIC = Topic.create("Bulk document change notification like reformat, etc.", DocumentBulkUpdateListener.class);
|
||||
|
||||
void updateStarted(@NotNull Document doc);
|
||||
void updateFinished(@NotNull Document doc);
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 259 B |
Binary file not shown.
|
After Width: | Height: | Size: 262 B |
@@ -58,7 +58,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D
|
||||
|
||||
private void addCustomFoldingRegionsRecursively(@Nullable FoldingStack foldingStack,
|
||||
@NotNull ASTNode node,
|
||||
List<FoldingDescriptor> descriptors,
|
||||
@NotNull List<FoldingDescriptor> descriptors,
|
||||
int currDepth) {
|
||||
FoldingStack localFoldingStack = isCustomFoldingRoot(node) || foldingStack == null ? new FoldingStack(node) : foldingStack;
|
||||
for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) {
|
||||
@@ -196,7 +196,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D
|
||||
}
|
||||
|
||||
private static class FoldingStack extends Stack<ASTNode> {
|
||||
private ASTNode owner;
|
||||
private final ASTNode owner;
|
||||
|
||||
public FoldingStack(@NotNull ASTNode owner) {
|
||||
super(1);
|
||||
@@ -205,7 +205,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D
|
||||
|
||||
@NotNull
|
||||
public ASTNode getOwner() {
|
||||
return this.owner;
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
@@ -93,8 +92,6 @@ public class TextPainter implements Printable {
|
||||
myFileName = fileName;
|
||||
mySegmentEnd = myDocument.getTextLength();
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
myFileType = psiFile.getFileType();
|
||||
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ public class ExternalToolPass extends TextEditorHighlightingPass {
|
||||
|
||||
private final Map<ExternalAnnotator, MyData> myAnnotator2DataMap;
|
||||
|
||||
private final ExternalToolPassFactory myExternalToolPassFactory;
|
||||
|
||||
private static class MyData {
|
||||
final PsiFile myPsiRoot;
|
||||
final Object myCollectedInfo;
|
||||
@@ -61,7 +63,8 @@ public class ExternalToolPass extends TextEditorHighlightingPass {
|
||||
}
|
||||
}
|
||||
|
||||
public ExternalToolPass(@NotNull PsiFile file,
|
||||
public ExternalToolPass(@NotNull ExternalToolPassFactory externalToolPassFactory,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull Editor editor,
|
||||
int startOffset,
|
||||
int endOffset) {
|
||||
@@ -72,6 +75,7 @@ public class ExternalToolPass extends TextEditorHighlightingPass {
|
||||
myAnnotationHolder = new AnnotationHolderImpl(new AnnotationSession(file));
|
||||
|
||||
myAnnotator2DataMap = new HashMap<ExternalAnnotator, MyData>();
|
||||
myExternalToolPassFactory = externalToolPassFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,7 +163,7 @@ public class ExternalToolPass extends TextEditorHighlightingPass {
|
||||
r.run();
|
||||
}
|
||||
else {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(r);
|
||||
myExternalToolPassFactory.scheduleExternalActivity(myFile, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-2
@@ -28,6 +28,8 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import com.intellij.util.ui.update.Update;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -38,10 +40,15 @@ import java.util.List;
|
||||
* @author cdr
|
||||
*/
|
||||
public class ExternalToolPassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory {
|
||||
private final MergingUpdateQueue myExternalActivitiesQueue;
|
||||
|
||||
public ExternalToolPassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) {
|
||||
super(project);
|
||||
// start after PostHighlightingPass completion since it could report errors that can prevent us to run
|
||||
highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{Pass.POST_UPDATE_ALL}, null, true, Pass.EXTERNAL_TOOLS);
|
||||
|
||||
myExternalActivitiesQueue = new MergingUpdateQueue("ExternalActivitiesQueue", 300, true, MergingUpdateQueue.ANY_COMPONENT, project,
|
||||
null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,11 +61,11 @@ public class ExternalToolPassFactory extends AbstractProjectComponent implements
|
||||
@Override
|
||||
@Nullable
|
||||
public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull final Editor editor) {
|
||||
TextRange textRange = file.getTextRange();
|
||||
TextRange textRange = FileStatusMap.getDirtyTextRange(editor, Pass.EXTERNAL_TOOLS) == null ? null : file.getTextRange();
|
||||
if (textRange == null || !externalAnnotatorsDefined(file)) {
|
||||
return null;
|
||||
}
|
||||
return new ExternalToolPass(file, editor, textRange.getStartOffset(), textRange.getEndOffset());
|
||||
return new ExternalToolPass(this, file, editor, textRange.getStartOffset(), textRange.getEndOffset());
|
||||
}
|
||||
|
||||
private static boolean externalAnnotatorsDefined(PsiFile file) {
|
||||
@@ -70,4 +77,13 @@ public class ExternalToolPassFactory extends AbstractProjectComponent implements
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void scheduleExternalActivity(@NotNull PsiFile file, @NotNull final Runnable r) {
|
||||
myExternalActivitiesQueue.queue(new Update(file) {
|
||||
@Override
|
||||
public void run() {
|
||||
r.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,7 +924,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
|
||||
@Override
|
||||
public boolean vetoesHiding() {
|
||||
return myChangeGuard || myDisposed;
|
||||
return myChangeGuard;
|
||||
}
|
||||
|
||||
public boolean isAvailableToUser() {
|
||||
|
||||
@@ -363,7 +363,9 @@ public class GridCellImpl implements GridCell {
|
||||
service.setSize(getDimensionKey(), size, myContext.getProject());
|
||||
if (myContext.getWindow() != 0) {
|
||||
final Window frame = SwingUtilities.getWindowAncestor(myPlaceholder);
|
||||
service.setLocation(getDimensionKey(), frame.getLocationOnScreen());
|
||||
if (frame != null) {
|
||||
service.setLocation(getDimensionKey(), frame.getLocationOnScreen());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,8 @@ public abstract class GotoActionBase extends AnAction {
|
||||
@Override
|
||||
public void onClose() {
|
||||
ourLastStrings.put(myInAction, Pair.create(popup.getEnteredText(), popup.getSelectedIndex()));
|
||||
if (startedAction.equals(myInAction)) {
|
||||
//noinspection ConstantConditions
|
||||
if (startedAction != null && startedAction.equals(myInAction)) {
|
||||
myInAction = null;
|
||||
}
|
||||
if (filter != null) {
|
||||
|
||||
@@ -253,8 +253,6 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
|
||||
myViewContentPanel = new JPanel();
|
||||
myPanel = new SimpleToolWindowPanel(true).setProvideQuickActions(false);
|
||||
myPanel.setContent(myViewContentPanel);
|
||||
|
||||
myPanel.setBorder(new ToolWindow.Border(true, false, false, false));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
+10
-1
@@ -16,10 +16,13 @@
|
||||
package com.intellij.ide.util.gotoByName;
|
||||
|
||||
import com.intellij.concurrency.JobUtil;
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.ide.util.NavigationItemListCellRenderer;
|
||||
import com.intellij.navigation.ChooseByNameContributor;
|
||||
import com.intellij.navigation.NavigationItem;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
@@ -109,7 +112,13 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModel
|
||||
try {
|
||||
for (NavigationItem item : contributor.getItemsByName(name, pattern, myProject, checkBoxState)) {
|
||||
if (item == null) {
|
||||
LOG.error("null item from contributor " + contributor + " for name " + name);
|
||||
final PluginId pluginId = PluginManager.getPluginByClassName(contributor.getClass().getName());
|
||||
if (pluginId != null) {
|
||||
LOG.error(new PluginException("null item from contributor " + contributor + " for name " + name, pluginId));
|
||||
}
|
||||
else {
|
||||
LOG.error("null item from contributor " + contributor + " for name " + name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,12 +70,15 @@ public class ModuleAttachProcessor extends ProjectAttachProcessor {
|
||||
token.finish();
|
||||
}
|
||||
}
|
||||
for(String file: projectDir.list()) {
|
||||
if (FileUtil.getExtension(file).equals("iml")) {
|
||||
VirtualFile imlFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(projectDir, file));
|
||||
if (imlFile != null) {
|
||||
attachModule(project, imlFile, callback);
|
||||
return true;
|
||||
final String[] files = projectDir.list();
|
||||
if (files != null) {
|
||||
for(String file: files) {
|
||||
if (FileUtil.getExtension(file).equals("iml")) {
|
||||
VirtualFile imlFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(projectDir, file));
|
||||
if (imlFile != null) {
|
||||
attachModule(project, imlFile, callback);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.event.DocumentListener;
|
||||
import com.intellij.openapi.editor.ex.DocumentBulkUpdateListener;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
|
||||
@@ -79,7 +80,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
private final List<Listener> myListeners = ContainerUtil.createEmptyCOWList();
|
||||
private final SmartPointerManagerImpl mySmartPointerManager;
|
||||
|
||||
public PsiDocumentManagerImpl(@NotNull Project project,
|
||||
public PsiDocumentManagerImpl(@NotNull final Project project,
|
||||
@NotNull PsiManager psiManager,
|
||||
@NotNull SmartPointerManager smartPointerManager,
|
||||
@NotNull EditorFactory editorFactory,
|
||||
@@ -105,6 +106,12 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
fireDocumentCreated(document, psiFile);
|
||||
}
|
||||
});
|
||||
bus.connect().subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() {
|
||||
@Override
|
||||
public void updateFinished(@NotNull Document doc) {
|
||||
documentCommitThread.queueCommit(project, doc, "Bulk update finished");
|
||||
}
|
||||
});
|
||||
ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() {
|
||||
@Override
|
||||
public void beforeWriteActionStart(Object action) {
|
||||
@@ -668,12 +675,13 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
|
||||
commitNecessary = true;
|
||||
}
|
||||
boolean fromRefresh = ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class);
|
||||
|
||||
if (commitNecessary) {
|
||||
myUncommittedDocuments.add(document);
|
||||
myDocumentCommitThread.log("PDI: added to uncommitted", null, false, document, event, myUncommittedDocuments);
|
||||
|
||||
myDocumentCommitThread.queueCommit(myProject, document, event);
|
||||
if (!fromRefresh && !((DocumentEx)document).isInBulkUpdate()) {
|
||||
myDocumentCommitThread.queueCommit(myProject, document, event);
|
||||
}
|
||||
}
|
||||
|
||||
// Consider that it's worth to perform complete re-parse instead of merge if the whole document text is replaced and
|
||||
@@ -683,7 +691,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE);
|
||||
}
|
||||
|
||||
if (commitNecessary && ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class)){
|
||||
if (commitNecessary && fromRefresh){
|
||||
commitDocument(document);
|
||||
}
|
||||
// avoid documents piling up during batch processing
|
||||
|
||||
+14
-1
@@ -20,12 +20,14 @@ import com.intellij.history.core.LocalHistoryFacade;
|
||||
import com.intellij.history.integration.IdeaGateway;
|
||||
import com.intellij.history.integration.ui.views.SelectionHistoryDialog;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.actions.VcsContext;
|
||||
import com.intellij.openapi.vcs.actions.VcsContextWrapper;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.vcsUtil.VcsSelection;
|
||||
import com.intellij.vcsUtil.VcsSelectionUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ShowSelectionHistoryAction extends ShowHistoryAction {
|
||||
@Override
|
||||
@@ -44,12 +46,23 @@ public class ShowSelectionHistoryAction extends ShowHistoryAction {
|
||||
return sel == null ? super.getText(e) : sel.getActionName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
if (e.getData(PlatformDataKeys.EDITOR) == null) {
|
||||
e.getPresentation().setVisible(false);
|
||||
}
|
||||
else {
|
||||
super.update(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(LocalHistoryFacade vcs, IdeaGateway gw, VirtualFile f, AnActionEvent e) {
|
||||
return super.isEnabled(vcs, gw, f, e) && !f.isDirectory() && getSelection(e) != null;
|
||||
}
|
||||
|
||||
private VcsSelection getSelection(AnActionEvent e) {
|
||||
@Nullable
|
||||
private static VcsSelection getSelection(AnActionEvent e) {
|
||||
VcsContext c = VcsContextWrapper.createCachedInstanceOn(e);
|
||||
return VcsSelectionUtil.getSelection(c);
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom
|
||||
boolean hasFocus) {
|
||||
if (value instanceof MyNode) {
|
||||
final MyNode node = ((MyNode)value);
|
||||
setIcon(node.getConfigurable().getIcon(expanded));
|
||||
setIcon(node.getIcon(expanded));
|
||||
final Font font = UIUtil.getTreeFont();
|
||||
if (node.isDisplayInBold()) {
|
||||
setFont(font.deriveFont(Font.BOLD));
|
||||
@@ -699,8 +699,8 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom
|
||||
throw new ConfigurationException("Name should contain non-space characters");
|
||||
}
|
||||
if (names.contains(name)) {
|
||||
final NamedConfigurable selectedConfugurable = getSelectedConfugurable();
|
||||
if (selectedConfugurable == null || !Comparing.strEqual(selectedConfugurable.getDisplayName(), name)) {
|
||||
final NamedConfigurable selectedConfigurable = getSelectedConfugurable();
|
||||
if (selectedConfigurable == null || !Comparing.strEqual(selectedConfigurable.getDisplayName(), name)) {
|
||||
selectNodeInTree(node);
|
||||
}
|
||||
throw new ConfigurationException(CommonBundle.message("smth.already.exist.error.message", prefix, name), title);
|
||||
@@ -836,6 +836,16 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom
|
||||
public void setDisplayInBold(boolean displayInBold) {
|
||||
myDisplayInBold = displayInBold;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Icon getIcon(boolean expanded) {
|
||||
// thanks to invokeLater() in TreeUtil.showAndSelect(), we can get calls to getIcon() after the tree has been disposed
|
||||
final NamedConfigurable configurable = getConfigurable();
|
||||
if (configurable != null) {
|
||||
return configurable.getIcon(expanded);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"ConstantConditions"})
|
||||
|
||||
@@ -56,7 +56,7 @@ public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent imp
|
||||
clear();
|
||||
|
||||
mySelected = selected;
|
||||
myFocused = tree.hasFocus();
|
||||
myFocused = isFocused();
|
||||
|
||||
// We paint background if and only if tree path is selected and tree has focus.
|
||||
// If path is selected and tree is not focused then we just paint focused border.
|
||||
@@ -104,7 +104,7 @@ public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent imp
|
||||
super.setIconOpaque(false);
|
||||
}
|
||||
else {
|
||||
super.setOpaque(myOpaque || selected && hasFocus || selected && tree.hasFocus()); // draw selection background even for non-opaque tree
|
||||
super.setOpaque(myOpaque || selected && hasFocus || selected && isFocused()); // draw selection background even for non-opaque tree
|
||||
}
|
||||
|
||||
if (tree.getUI() instanceof UIUtil.MacTreeUI) {
|
||||
@@ -121,6 +121,10 @@ public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent imp
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean isFocused() {
|
||||
return myTree.hasFocus();
|
||||
}
|
||||
|
||||
public void setOpaque(boolean isOpaque) {
|
||||
myOpaque = isOpaque;
|
||||
super.setOpaque(isOpaque);
|
||||
|
||||
@@ -90,6 +90,15 @@ public abstract class HtmlListCellRenderer<T> extends ListCellRendererWrapper<T>
|
||||
}
|
||||
}
|
||||
|
||||
public void append(SimpleColoredText text) {
|
||||
int length = text.getTexts().size();
|
||||
for (int i = 0; i < length; i++) {
|
||||
String fragment = text.getTexts().get(i);
|
||||
SimpleTextAttributes attributes = text.getAttributes().get(i);
|
||||
append(fragment, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
private static void formatStyle(final StringBuilder builder, final SimpleTextAttributes attributes) {
|
||||
final Color fgColor = attributes.getFgColor();
|
||||
final Color bgColor = attributes.getBgColor();
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package com.intellij.ui;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.ui.LabeledComponent;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
@@ -27,6 +29,8 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class RawCommandLineEditor extends JPanel {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.RawCommandLineEditor");
|
||||
|
||||
private final TextFieldWithBrowseButton myTextField;
|
||||
private String myDialogCaption = "";
|
||||
|
||||
@@ -34,6 +38,14 @@ public class RawCommandLineEditor extends JPanel {
|
||||
super(new BorderLayout());
|
||||
myTextField = new TextFieldWithBrowseButton(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (myDialogCaption == null) {
|
||||
Container parent = getParent();
|
||||
if (parent instanceof LabeledComponent) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
LOG.error("Did not call RawCommandLineEditor.setDialogCaption() in " + parent);
|
||||
myDialogCaption = "Parameters";
|
||||
}
|
||||
Messages.showTextAreaDialog(myTextField.getTextField(), myDialogCaption, "EditParametersPopupWindow");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -81,4 +81,15 @@ public class SimpleColoredText {
|
||||
public ArrayList<SimpleTextAttributes> getAttributes() {
|
||||
return myAttributes;
|
||||
}
|
||||
|
||||
public SimpleColoredText derive(SimpleTextAttributes attributes, boolean override) {
|
||||
SimpleColoredText result = new SimpleColoredText();
|
||||
for (int i = 0; i < myTexts.size(); i++) {
|
||||
SimpleTextAttributes overridden = override
|
||||
? SimpleTextAttributes.merge(myAttributes.get(i), attributes)
|
||||
: SimpleTextAttributes.merge(attributes, myAttributes.get(i));
|
||||
result.append(myTexts.get(i), overridden);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +337,9 @@ public class JBTabsImpl extends JComponent
|
||||
|
||||
BufferedImage img;
|
||||
if (cmp.isShowing()) {
|
||||
img = new BufferedImage(cmp.getWidth(), cmp.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
final int width = cmp.getWidth();
|
||||
final int height = cmp.getHeight();
|
||||
img = new BufferedImage(width > 0 ? width : 500, height > 0 ? height : 500, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = img.createGraphics();
|
||||
cmp.paint(g);
|
||||
} else {
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.ui.SimpleToolWindowPanel;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
import com.intellij.openapi.util.*;
|
||||
@@ -403,7 +404,7 @@ public class EventLog implements Notifications {
|
||||
|
||||
myProjectModel.addNotification(notification);
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!ShutDownTracker.isShutdownHookRunning() && !myProject.isDisposed()) {
|
||||
|
||||
+13
-2
@@ -16,6 +16,7 @@
|
||||
package com.intellij.openapi.editor.highlighter;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
|
||||
@@ -32,6 +33,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @author yole
|
||||
*/
|
||||
public class EditorHighlighterFactoryImpl extends EditorHighlighterFactory {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.highlighter.EditorHighlighterFactoryImpl");
|
||||
|
||||
@Override
|
||||
public EditorHighlighter createEditorHighlighter(SyntaxHighlighter highlighter, final EditorColorsScheme colors) {
|
||||
if (highlighter == null) highlighter = new PlainSyntaxHighlighter();
|
||||
@@ -74,8 +77,16 @@ public class EditorHighlighterFactoryImpl extends EditorHighlighterFactory {
|
||||
final ContentBasedFileSubstitutor[] processors = Extensions.getExtensions(ContentBasedFileSubstitutor.EP_NAME);
|
||||
SyntaxHighlighter highlighter = null;
|
||||
for (ContentBasedFileSubstitutor processor : processors) {
|
||||
if (processor.isApplicable(project, vFile) && processor instanceof ContentBasedClassFileProcessor) {
|
||||
highlighter = ((ContentBasedClassFileProcessor) processor).createHighlighter(project, vFile);
|
||||
boolean applicable;
|
||||
try {
|
||||
applicable = processor.isApplicable(project, vFile);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
continue;
|
||||
}
|
||||
if (applicable && processor instanceof ContentBasedClassFileProcessor) {
|
||||
highlighter = ((ContentBasedClassFileProcessor)processor).createHighlighter(project, vFile);
|
||||
}
|
||||
}
|
||||
if (highlighter == null) {
|
||||
|
||||
@@ -5803,7 +5803,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
if (last != null && !(last instanceof EditorComponentImpl)) return;
|
||||
|
||||
final Editor editor = getEditor(source);
|
||||
if (action == MOVE && !editor.isViewer()) {
|
||||
if (action == MOVE && !editor.isViewer() && myDraggedRange != null) {
|
||||
if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), editor.getProject())) {
|
||||
return;
|
||||
}
|
||||
|
||||
+1
@@ -1647,6 +1647,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
|
||||
if (newFilePair == null) continue;
|
||||
|
||||
VirtualFile newFile = newFilePair.first;
|
||||
if (newFile == null) continue;
|
||||
|
||||
// already open
|
||||
if (eachWindow.findFileIndex(newFile) != -1) continue;
|
||||
|
||||
+1
@@ -50,6 +50,7 @@ public class CheckForUpdateAction extends AnAction implements DumbAware {
|
||||
ProgressManager.getInstance().run(new Task.Modal(project, "Checking for updates", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
indicator.setIndeterminate(true);
|
||||
final CheckForUpdateResult result = UpdateChecker.checkForUpdates(instance, PropertiesComponent.getInstance(),
|
||||
true
|
||||
);
|
||||
|
||||
+6
-4
@@ -219,11 +219,13 @@ public class VirtualFilePointerImpl extends UserDataHolderBase implements Virtua
|
||||
disposed = true;
|
||||
|
||||
final Pair<VirtualFile, String> pair = myFileAndUrl;
|
||||
if (pair.first != null) {
|
||||
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(pair.first.getUrl(), myListener);
|
||||
VirtualFile file = pair.first;
|
||||
if (file != null) {
|
||||
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(file.getUrl(), myListener);
|
||||
}
|
||||
if (pair.second != null) {
|
||||
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(pair.second, myListener);
|
||||
String url = pair.second;
|
||||
if (url != null && (file == null || !url.equals(file.getUrl()))) {
|
||||
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(url, myListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-8
@@ -72,7 +72,6 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
|
||||
synchronized void clearPointerCaches(String url, VirtualFilePointerListener listener) {
|
||||
TreeMap<String, VirtualFilePointerImpl> urlToPointer = myUrlToPointerMaps.get(listener);
|
||||
if (urlToPointer == null && ApplicationManager.getApplication().isUnitTestMode()) return;
|
||||
assert urlToPointer != null;
|
||||
urlToPointer.remove(VfsUtil.urlToPath(url));
|
||||
if (urlToPointer.isEmpty()) {
|
||||
@@ -148,12 +147,6 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
return url.substring(separatorIndex + JarFileSystem.JAR_SEPARATOR.length());
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public synchronized void cleanupForNextTest() {
|
||||
myUrlToPointerMaps.clear();
|
||||
myContainers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #create(String, com.intellij.openapi.Disposable, com.intellij.openapi.vfs.pointers.VirtualFilePointerListener)
|
||||
*/
|
||||
@@ -339,7 +332,7 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
VirtualFilePointerListener listener = entry.getKey();
|
||||
TreeMap<String, VirtualFilePointerImpl> map = entry.getValue();
|
||||
for (VirtualFilePointerImpl pointer : map.values()) {
|
||||
myUrlToPointerMaps.clear();
|
||||
//myUrlToPointerMaps.clear();
|
||||
pointer.throwNotDisposedError("Not disposed pointer: listener="+listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowAnchor;
|
||||
import com.intellij.openapi.wm.ToolWindowType;
|
||||
@@ -430,7 +431,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable {
|
||||
}
|
||||
};
|
||||
|
||||
myButton.setHoveringEnabled(true);
|
||||
myButton.setHoveringEnabled(!SystemInfo.isMac);
|
||||
setContent(myButton);
|
||||
setOpaque(false);
|
||||
|
||||
|
||||
@@ -128,8 +128,11 @@ public class PositionPanel extends EditorBasedWidget implements StatusBarWidget.
|
||||
public void caretPositionChanged(final CaretEvent e) {
|
||||
final Editor editor = e.getEditor();
|
||||
Project project = editor.getProject();
|
||||
if (project != null && !project.isDisposed() && FileEditorManager.getInstance(project).getSelectedTextEditor() == e.getEditor()) {
|
||||
updatePosition(editor);
|
||||
if (project != null && !project.isDisposed()) {
|
||||
final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); // returns null for default project
|
||||
if (fileEditorManager != null && fileEditorManager.getSelectedTextEditor() == e.getEditor()) {
|
||||
updatePosition(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,11 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
|
||||
setErrorText("Project name can't be empty");
|
||||
return;
|
||||
}
|
||||
if (myLocationField.getText().indexOf('$') >= 0) {
|
||||
setOKActionEnabled(false);
|
||||
setErrorText("Project directory name must not contain the $ character");
|
||||
return;
|
||||
}
|
||||
DirectoryProjectGenerator generator = getProjectGenerator();
|
||||
if (generator != null) {
|
||||
String baseDirPath = myLocationField.getTextField().getText();
|
||||
|
||||
@@ -424,6 +424,39 @@ public class VirtualFilePointerTest extends PlatformLangTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
public void testDoubleDispose() throws IOException {
|
||||
final File tempDir = createTempDirectory();
|
||||
final File file = new File(tempDir, "f1");
|
||||
boolean created = file.createNewFile();
|
||||
assertTrue(created);
|
||||
|
||||
final VirtualFile[] vFile = new VirtualFile[1];
|
||||
final String url = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, file.getCanonicalPath().replace(File.separatorChar, '/'));
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
vFile[0] = VirtualFileManager.getInstance().refreshAndFindFileByUrl(url);
|
||||
}
|
||||
});
|
||||
|
||||
Disposable disposable = Disposer.newDisposable();
|
||||
final VirtualFilePointer pointer = myVirtualFilePointerManager.create(vFile[0], disposable, new VirtualFilePointerListener() {
|
||||
@Override
|
||||
public void beforeValidityChanged(VirtualFilePointer[] pointers) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validityChanged(VirtualFilePointer[] pointers) {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assertTrue(pointer.isValid());
|
||||
|
||||
Disposer.dispose(disposable);
|
||||
assertFalse(pointer.isValid());
|
||||
}
|
||||
|
||||
public void testThreads() throws IOException, InterruptedException {
|
||||
final File ioTempDir = createTempDirectory();
|
||||
final File ioPtrBase = new File(ioTempDir, "parent");
|
||||
|
||||
@@ -53,11 +53,9 @@ import com.intellij.openapi.util.EmptyRunnable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
|
||||
import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
@@ -339,10 +337,6 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
|
||||
LocalHistoryImpl.getInstanceImpl().cleanupForNextTest();
|
||||
|
||||
VirtualFilePointerManagerImpl virtualFilePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
|
||||
if (virtualFilePointerManager != null) {
|
||||
virtualFilePointerManager.cleanupForNextTest();
|
||||
}
|
||||
PatchedWeakReference.clearAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,10 @@ public class Comparing {
|
||||
return o1 < o2 ? -1 : o1 == o2 ? 0 : 1;
|
||||
}
|
||||
|
||||
public static int compare(boolean o1, boolean o2) {
|
||||
return o1 == o2 ? 0 : o1 ? 1 : -1;
|
||||
}
|
||||
|
||||
public static int compare(int o1, int o2) {
|
||||
return o1 < o2 ? -1 : o1 == o2 ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ activity.class.not.specified.error=Activity class not specified
|
||||
not.activity.subclass.error={0} is not an Activity subclass
|
||||
no.facet.error=No Android facet found for {0}
|
||||
android.logcat.tab.title=Logcat
|
||||
android.logcat.title=Android Logcat
|
||||
android.adb.logs.tab.title=ADB logs
|
||||
android.logcat.title=Android
|
||||
android.logcat.error.dialog.title=Android Logcat Error
|
||||
android.logcat.color.page.name=Android Logcat
|
||||
warning.level.title=Warning
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
<annotator language="XML" implementationClass="org.jetbrains.android.AndroidColorAnnotator" order="first"/>
|
||||
<xml.elementDescriptorProvider implementation="org.jetbrains.android.dom.AndroidDomElementDescriptorProvider" order="first"/>
|
||||
|
||||
<facet.toolWindow id="Android Logcat"
|
||||
<facet.toolWindow id="Android"
|
||||
facetIdList="android"
|
||||
anchor="bottom"
|
||||
icon="/icons/android.png"
|
||||
|
||||
@@ -29,7 +29,9 @@ class ClassesAndJarsValidityState implements ValidityState {
|
||||
}
|
||||
}
|
||||
else if (StdFileTypes.CLASS.equals(file.getFileType()) || file.getFileType() instanceof ArchiveFileType) {
|
||||
myFiles.put(file.getPath(), file.getTimeStamp());
|
||||
if (file.isValid()) {
|
||||
myFiles.put(file.getPath(), file.getTimeStamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ public class AndroidDomExtender extends DomExtender<AndroidDomElement> {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
|
||||
@Nullable
|
||||
public PsiClass compute() {
|
||||
return c.getSuperClass();
|
||||
return c.isValid() ? c.getSuperClass() : null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class ManifestDomFileDescription extends DomFileDescription<Manifest> {
|
||||
return false;
|
||||
}
|
||||
final Module module = ModuleUtil.findModuleForPsiElement(file);
|
||||
return module == null || AndroidFacet.getInstance(module) != null;
|
||||
return module == null || !module.isDisposed() && AndroidFacet.getInstance(module) != null;
|
||||
}
|
||||
|
||||
protected void initializeFileDescription() {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.jetbrains.android.logcat;
|
||||
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AdbErrors {
|
||||
private AdbErrors() {
|
||||
}
|
||||
|
||||
private static volatile List<String> ourAdbErrorList;
|
||||
|
||||
@NotNull
|
||||
public static synchronized String[] getErrors() {
|
||||
return ourAdbErrorList != null ? ArrayUtil.toStringArray(ourAdbErrorList) : ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
}
|
||||
|
||||
public static synchronized void clear() {
|
||||
if (ourAdbErrorList != null) {
|
||||
ourAdbErrorList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void reportError(@NotNull String message, @Nullable String tag) {
|
||||
final String fullMessage = tag != null ? tag + ": " + message : message;
|
||||
if (ourAdbErrorList == null) {
|
||||
ourAdbErrorList = new ArrayList<String>();
|
||||
}
|
||||
ourAdbErrorList.add(fullMessage);
|
||||
}
|
||||
}
|
||||
+73
-6
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.jetbrains.android.logcat;
|
||||
|
||||
import com.android.ddmlib.Log;
|
||||
import com.intellij.ProjectTopics;
|
||||
import com.intellij.execution.filters.HyperlinkInfo;
|
||||
import com.intellij.execution.impl.ConsoleViewImpl;
|
||||
import com.intellij.execution.ui.ConsoleView;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.facet.ProjectFacetManager;
|
||||
@@ -34,6 +36,7 @@ import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter;
|
||||
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import com.intellij.ui.content.impl.ContentImpl;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.maven.AndroidMavenUtil;
|
||||
@@ -90,12 +93,34 @@ public class AndroidLogcatToolWindowFactory implements ToolWindowFactory {
|
||||
|
||||
JPanel contentPanel = view.getContentPanel();
|
||||
final ContentManager contentManager = toolWindow.getContentManager();
|
||||
final Content content = contentManager.getFactory().createContent(contentPanel, null, false);
|
||||
content.setDisposer(view);
|
||||
content.setCloseable(false);
|
||||
content.setPreferredFocusableComponent(contentPanel);
|
||||
contentManager.addContent(content);
|
||||
contentManager.setSelectedContent(content, true);
|
||||
|
||||
final Content logcatContent =
|
||||
contentManager.getFactory().createContent(contentPanel, AndroidBundle.message("android.logcat.tab.title"), false);
|
||||
logcatContent.setDisposer(view);
|
||||
logcatContent.setCloseable(false);
|
||||
logcatContent.setPreferredFocusableComponent(contentPanel);
|
||||
contentManager.addContent(logcatContent);
|
||||
contentManager.setSelectedContent(logcatContent, true);
|
||||
|
||||
final ConsoleView console = new ConsoleViewImpl(project, false);
|
||||
final Content adbLogsContent = new ContentImpl(console.getComponent(), AndroidBundle.message("android.adb.logs.tab.title"), false);
|
||||
adbLogsContent.setCloseable(false);
|
||||
contentManager.addContent(adbLogsContent);
|
||||
|
||||
//noinspection UnnecessaryFullyQualifiedName
|
||||
com.android.ddmlib.Log.setLogOutput(new Log.ILogOutput() {
|
||||
@Override
|
||||
public void printLog(Log.LogLevel logLevel, String tag, String message) {
|
||||
reportAdbLogMessage(logLevel, tag, message, console);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printAndPromptLog(Log.LogLevel logLevel, String tag, String message) {
|
||||
// todo: should we show dialog?
|
||||
reportAdbLogMessage(logLevel, tag, message, console);
|
||||
}
|
||||
});
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
view.activate();
|
||||
@@ -107,6 +132,48 @@ public class AndroidLogcatToolWindowFactory implements ToolWindowFactory {
|
||||
});
|
||||
}
|
||||
|
||||
private static void reportAdbLogMessage(Log.LogLevel logLevel, String tag, String message, @NotNull ConsoleView consoleView) {
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
if (logLevel == null) {
|
||||
logLevel = Log.LogLevel.INFO;
|
||||
}
|
||||
|
||||
if (logLevel == Log.LogLevel.ERROR || logLevel == Log.LogLevel.ASSERT) {
|
||||
AdbErrors.reportError(message, tag);
|
||||
}
|
||||
|
||||
final ConsoleViewContentType contentType = toConsoleViewContentType(logLevel);
|
||||
if (contentType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String fullMessage = tag != null ? tag + ": " + message : message;
|
||||
consoleView.print(fullMessage + '\n', contentType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ConsoleViewContentType toConsoleViewContentType(@NotNull Log.LogLevel logLevel) {
|
||||
switch (logLevel) {
|
||||
case VERBOSE:
|
||||
return null;
|
||||
case DEBUG:
|
||||
return null;
|
||||
case INFO:
|
||||
return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.INFO);
|
||||
case WARN:
|
||||
return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.WARNING);
|
||||
case ERROR:
|
||||
return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.ERROR);
|
||||
case ASSERT:
|
||||
return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.ASSERT);
|
||||
default:
|
||||
assert false : "Unknown log level " + logLevel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void checkFacetAndSdk(Project project, AndroidLogcatToolWindowView view) {
|
||||
final List<AndroidFacet> facets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID);
|
||||
final ConsoleView console = view.getLogConsole().getConsole();
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.android.sdk;
|
||||
|
||||
import com.android.ddmlib.AndroidDebugBridge;
|
||||
import com.android.ddmlib.DdmPreferences;
|
||||
import com.android.ddmlib.Log;
|
||||
import com.android.sdklib.*;
|
||||
import com.android.sdklib.internal.project.ProjectProperties;
|
||||
import com.intellij.CommonBundle;
|
||||
@@ -33,6 +34,7 @@ import com.intellij.reference.SoftReference;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.android.actions.AndroidEnableAdbServiceAction;
|
||||
import org.jetbrains.android.logcat.AdbErrors;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.android.util.BufferingFileWrapper;
|
||||
@@ -182,12 +184,15 @@ public class AndroidSdkData {
|
||||
return getLocation().hashCode();
|
||||
}
|
||||
|
||||
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
|
||||
private boolean initializeDdmlib(@NotNull Project project) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
while (true) {
|
||||
final MyInitializeDdmlibTask task = new MyInitializeDdmlibTask(project);
|
||||
|
||||
AdbErrors.clear();
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -205,25 +210,33 @@ public class AndroidSdkData {
|
||||
|
||||
boolean finished = task.isFinished();
|
||||
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
myAdbCrashed = !finished;
|
||||
|
||||
if (task.isCanceled()) {
|
||||
myAdbCrashed = !finished;
|
||||
forceInterrupt(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!finished) {
|
||||
int result = Messages
|
||||
.showOkCancelDialog(project,
|
||||
"ADB not responding. Please, kill \"" + SdkConstants.FN_ADB + "\" process manually and click 'Retry'",
|
||||
CommonBundle.getErrorTitle(), "&Retry", "&Cancel", Messages.getErrorIcon());
|
||||
myAdbCrashed = false;
|
||||
|
||||
if (result == 1) {
|
||||
if (!finished) {
|
||||
final String adbErrorString = combine(AdbErrors.getErrors());
|
||||
final int result = Messages.showDialog(project, "ADB not responding. You can wait more, or kill \"" +
|
||||
SdkConstants.FN_ADB +
|
||||
"\" process manually and click 'Restart'" +
|
||||
(adbErrorString.length() > 0 ? "\nErrors from ADB:\n" + adbErrorString : ""),
|
||||
CommonBundle.getErrorTitle(), new String[]{"&Wait more", "&Restart", "&Cancel"}, 0,
|
||||
Messages.getErrorIcon());
|
||||
if (result == 2) {
|
||||
// cancel
|
||||
myAdbCrashed = true;
|
||||
forceInterrupt(t);
|
||||
return false;
|
||||
}
|
||||
retryWas = true;
|
||||
else if (result == 1) {
|
||||
// restart
|
||||
myAdbCrashed = true;
|
||||
retryWas = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +249,19 @@ public class AndroidSdkData {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String combine(@NotNull String[] strs) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (String str : strs) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append('\n');
|
||||
}
|
||||
builder.append(str);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"BusyWait"})
|
||||
private static void forceInterrupt(Thread thread) {
|
||||
/*
|
||||
@@ -262,6 +288,7 @@ public class AndroidSdkData {
|
||||
synchronized (myDdmsLock) {
|
||||
if (!myDdmLibInitialized) {
|
||||
myDdmLibInitialized = true;
|
||||
DdmPreferences.setLogLevel(Log.LogLevel.INFO.getStringValue());
|
||||
DdmPreferences.setTimeOut(AndroidUtils.TIMEOUT);
|
||||
AndroidDebugBridge.init(AndroidEnableAdbServiceAction.isAdbServiceEnabled());
|
||||
LOG.info("DDMLib initialized");
|
||||
|
||||
+2
-5
@@ -18,7 +18,6 @@ package org.jetbrains.generate.tostring;
|
||||
import com.intellij.codeInsight.generation.PsiElementClassMember;
|
||||
import com.intellij.codeInsight.generation.PsiFieldMember;
|
||||
import com.intellij.codeInsight.generation.PsiMethodMember;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
@@ -31,7 +30,6 @@ import org.jetbrains.generate.tostring.exception.GenerateCodeException;
|
||||
import org.jetbrains.generate.tostring.exception.PluginException;
|
||||
import org.jetbrains.generate.tostring.psi.PsiAdapter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -142,9 +140,8 @@ public class GenerateToStringUtils {
|
||||
* @param e the caused exception.
|
||||
* @throws RuntimeException is thrown for severe exceptions
|
||||
*/
|
||||
public static void handleExeption(Project project, Exception e) throws RuntimeException {
|
||||
e.printStackTrace(); // must print stacktrace to see caused in IDEA log / console
|
||||
log.error(e);
|
||||
public static void handleException(Project project, Exception e) throws RuntimeException {
|
||||
log.info(e);
|
||||
|
||||
if (e instanceof GenerateCodeException) {
|
||||
// code generation error - display velocity errror in error dialog so user can identify problem quicker
|
||||
|
||||
+1
-1
@@ -382,7 +382,7 @@ public class GenerateToStringWorker {
|
||||
new GenerateToStringWorker(clazz, editor, insertAtOverride).execute(selectedMemebers, template);
|
||||
}
|
||||
catch (Exception e) {
|
||||
GenerateToStringUtils.handleExeption(clazz.getProject(), e);
|
||||
GenerateToStringUtils.handleException(clazz.getProject(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -142,7 +142,11 @@ public class GitCompareWithBranchAction extends DumbAwareAction {
|
||||
if (repository == null || repository.isFresh() || noBranchesToCompare(repository)) {
|
||||
presentation.setEnabled(false);
|
||||
presentation.setVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
presentation.setEnabled(true);
|
||||
presentation.setVisible(true);
|
||||
}
|
||||
|
||||
private static boolean noBranchesToCompare(@NotNull GitRepository repository) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package git4idea.actions;
|
||||
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
@@ -30,12 +31,12 @@ import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsDirectoryMapping;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.vcsUtil.VcsFileUtil;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.commands.GitCommandResult;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -78,13 +79,13 @@ public class GitInit extends DumbAwareAction {
|
||||
}
|
||||
}
|
||||
|
||||
GitVcs vcs = GitVcs.getInstance(project);
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
try {
|
||||
git.init(project, root);
|
||||
} catch (VcsException ex) {
|
||||
if (vcs == null || vcs.getExecutableValidator().isExecutableValid()) {
|
||||
GitUIUtil.showOperationErrors(project, Collections.singleton(ex), "git init");
|
||||
GitVcs vcs = GitVcs.getInstance(project);
|
||||
GitCommandResult result = git.init(project, root);
|
||||
if (!result.success()) {
|
||||
if (vcs != null && vcs.getExecutableValidator().isExecutableValid()) {
|
||||
GitUIUtil.notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, project, "Git init failed", result.getErrorOutputAsHtmlString(),
|
||||
NotificationType.ERROR, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.Set;
|
||||
*/
|
||||
public interface Git {
|
||||
|
||||
void init(Project project, VirtualFile root) throws VcsException;
|
||||
GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners);
|
||||
|
||||
@NotNull
|
||||
Set<VirtualFile> untrackedFiles(@NotNull Project project,
|
||||
|
||||
@@ -50,17 +50,15 @@ public class GitImpl implements Git {
|
||||
|
||||
/**
|
||||
* Calls 'git init' on the specified directory.
|
||||
* // TODO use common format
|
||||
*/
|
||||
@Override
|
||||
public void init(Project project, VirtualFile root) throws VcsException {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.INIT);
|
||||
h.setSilent(false);
|
||||
h.setNoSSH(true);
|
||||
h.run();
|
||||
if (!h.errors().isEmpty()) {
|
||||
throw h.errors().get(0);
|
||||
public GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners) {
|
||||
GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT);
|
||||
for (GitLineHandlerListener listener : listeners) {
|
||||
h.addLineListener(listener);
|
||||
}
|
||||
h.setSilent(false);
|
||||
return run(h);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,11 +103,11 @@ public class CherryPicker {
|
||||
public void run() {
|
||||
moveToCorrectLists();
|
||||
}
|
||||
}, InvokeAfterUpdateMode.SYNCHRONOUS_CANCELLABLE, "", new Consumer<VcsDirtyScopeManager>() {
|
||||
}, InvokeAfterUpdateMode.SILENT, "", new Consumer<VcsDirtyScopeManager>() {
|
||||
public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) {
|
||||
vcsDirtyScopeManager.filePathsDirty(getAllChangedFiles(), null);
|
||||
}
|
||||
}, ModalityState.defaultModalityState());
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
private void showResults() {
|
||||
|
||||
@@ -20,13 +20,13 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsDirectoryMapping;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import git4idea.Notificator;
|
||||
import git4idea.PlatformFacade;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.commands.GitCommandResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@@ -77,15 +77,15 @@ public class GitIntegrationEnabler {
|
||||
}
|
||||
|
||||
private boolean gitInitOrNotifyError(@NotNull Notificator notificator, @NotNull final VirtualFile projectDir) {
|
||||
try {
|
||||
myGit.init(myProject, projectDir);
|
||||
GitCommandResult result = myGit.init(myProject, projectDir);
|
||||
if (result.success()) {
|
||||
refreshGitDir(projectDir);
|
||||
notificator.notifySuccess("", "Created Git repository in \n" + projectDir.getPresentableUrl());
|
||||
return true;
|
||||
}
|
||||
catch (VcsException e) {
|
||||
notificator.notifyError("Couldn't git init " + projectDir.getPresentableUrl(), e.getMessage());
|
||||
LOG.error(e);
|
||||
else {
|
||||
notificator.notifyError("Couldn't git init " + projectDir.getPresentableUrl(), result.getErrorOutputAsHtmlString());
|
||||
LOG.info(result.getErrorOutputAsHtmlString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import git4idea.commands.GitCommandResult
|
||||
import git4idea.commands.GitLineHandlerListener
|
||||
import git4idea.push.GitPushSpec
|
||||
import git4idea.repo.GitRepository
|
||||
import org.jetbrains.annotations.NotNull
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -30,8 +31,9 @@ import git4idea.repo.GitRepository
|
||||
class MockGit implements Git {
|
||||
|
||||
@Override
|
||||
void init(Project project, VirtualFile root) {
|
||||
GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners) {
|
||||
new File(root.path, ".git").mkdir()
|
||||
new GitCommandResult(true, 0, Collections.emptyList(), Collections.emptyList())
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationInfoEx;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
@@ -17,12 +18,10 @@ import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsOutgoingChangesProvider;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
|
||||
import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode;
|
||||
import com.intellij.openapi.vcs.changes.actions.RefreshAction;
|
||||
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
@@ -32,11 +31,13 @@ import git4idea.GitUtil;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.actions.BasicAction;
|
||||
import git4idea.actions.GitInit;
|
||||
import git4idea.push.GitPushUtils;
|
||||
import git4idea.commands.*;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import git4idea.push.GitPushUtils;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.repo.GitRepositoryManager;
|
||||
import git4idea.util.GitFileUtils;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import org.jetbrains.plugins.github.ui.GithubShareDialog;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -129,12 +130,13 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
Messages.showErrorDialog(e1.getMessage(), "Failed to create new GitHub repository");
|
||||
return;
|
||||
}
|
||||
bindToGithub(project, root, gitDetected, settings.getLogin(), name);
|
||||
Notifications.Bus.notify(new Notification("github", "Success", "Successfully created project ''" + name + "'' on github",
|
||||
NotificationType.INFORMATION));
|
||||
if (bindToGithub(project, root, gitDetected, settings.getLogin(), name)) {
|
||||
Notifications.Bus.notify(new Notification("github", "Success", "Successfully created project ''" + name + "'' on github",
|
||||
NotificationType.INFORMATION));
|
||||
}
|
||||
}
|
||||
|
||||
private void bindToGithub(final Project project, final VirtualFile root, final boolean gitDetected, final String login, final String name) {
|
||||
private boolean bindToGithub(final Project project, final VirtualFile root, final boolean gitDetected, final String login, String name) {
|
||||
LOG.info("Binding local project with GitHub");
|
||||
// creating empty git repo if git isnot initialized
|
||||
if (!gitDetected) {
|
||||
@@ -145,7 +147,7 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
if (!h.errors().isEmpty()) {
|
||||
GitUIUtil.showOperationErrors(project, h.errors(), "git init");
|
||||
LOG.info("Failed to create empty git repo: " + h.errors());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
final ProgressManager manager = ProgressManager.getInstance();
|
||||
manager.runProcessWithProgressSynchronously(new Runnable() {
|
||||
@@ -157,7 +159,9 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
}
|
||||
|
||||
// In this case we should create sample commit for binding project
|
||||
performFirstCommitIfRequired(project, root);
|
||||
if (!performFirstCommitIfRequired(project, root)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//git remote add origin git@github.com:login/name.git
|
||||
LOG.info("Adding GitHub as a remote host");
|
||||
@@ -169,13 +173,13 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
addRemoteHandler.run();
|
||||
if (addRemoteHandler.getExitCode() != 0) {
|
||||
Messages.showErrorDialog("Failed to add GitHub repository as remote", "Failed to add GitHub repository as remote");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
Messages.showErrorDialog(e.getMessage(), "Failed to add GitHub repository as remote");
|
||||
LOG.info("Failed to add GitHub as remote: " + e.getMessage());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
//git push origin master
|
||||
@@ -198,6 +202,7 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
}
|
||||
// refresh vcs manually
|
||||
RefreshAction.doRefresh(project);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean performFirstCommitIfRequired(final Project project, final VirtualFile root) {
|
||||
@@ -206,20 +211,21 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
Messages.showErrorDialog(project, "Cannot find git initialized", "Failed to share");
|
||||
return false;
|
||||
}
|
||||
final VcsOutgoingChangesProvider<CommittedChangeList> provider = gitVcs.getOutgoingChangesProvider();
|
||||
if (provider == null) {
|
||||
Messages.showErrorDialog(project, "Cannot find git initialized", "Failed to share");
|
||||
|
||||
GitRepositoryManager repositoryManager = ServiceManager.getService(project, GitRepositoryManager.class);
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
if (repositoryManager == null || git == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (!provider.getOutgoingChanges(root, false).getSecond().isEmpty()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
Messages.showErrorDialog(project, e.getMessage(), "Failed to share");
|
||||
GitRepository repository = repositoryManager.getRepositoryForRoot(root);
|
||||
if (repository == null) {
|
||||
Messages.showErrorDialog(project, "Cannot find git repository for root " + root, "Failed to share");
|
||||
return false;
|
||||
}
|
||||
if (!repository.isFresh()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Ref<Exception> exceptionRef = new Ref<Exception>();
|
||||
// Creating or modifying readme file
|
||||
LOG.info("Touching file 'README' for initial commit");
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<body>
|
||||
|
||||
This inspection reports on unnecessary Groovy assignment statement
|
||||
<br><small>Powered by InspectorGroovy</small>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports on unnecessary Groovy incrementing and decrementing expressions
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
@@ -408,6 +408,9 @@
|
||||
<localInspection language="Groovy" groupPath="Groovy" shortName="GroovyUnusedAssignment" bundle="org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle"
|
||||
key="unused.assignment" groupKey="groovy.dfa.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.plugins.groovy.codeInspection.unusedDef.UnusedDefInspection"/>
|
||||
<localInspection language="Groovy" groupPath="Groovy" shortName="GroovyUnusedIncOrDec" bundle="org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle"
|
||||
key="unused.inc.dec" groupKey="groovy.dfa.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.plugins.groovy.codeInspection.confusing.GrUnusedIncDecInspection"/>
|
||||
<localInspection language="Groovy" groupPath="Groovy" shortName="GroovyVariableNotAssigned" bundle="org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle"
|
||||
key="unassigned.access" groupKey="groovy.dfa.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.plugins.groovy.codeInspection.unassignedVariable.UnassignedVariableAccessInspection"/>
|
||||
|
||||
+1
@@ -82,6 +82,7 @@ public class DumpGroovyControlFlowAction extends AnAction implements DumbAware {
|
||||
}
|
||||
|
||||
private static void passInner(GrControlFlowOwner owner) {
|
||||
System.out.println(owner.getText());
|
||||
System.out.println(ControlFlowUtils.dumpControlFlow(owner.getControlFlow()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
|
||||
for (PsiReference reference : ReferencesSearch.search(var, new LocalSearchScope(scope)).findAll()) {
|
||||
if (reference instanceof GrReferenceExpression &&
|
||||
(PsiUtil.isLValue((GrReferenceExpression)reference) ||
|
||||
((GrReferenceExpression)reference).getParent() instanceof GrPostfixExpression)) {
|
||||
((GrReferenceExpression)reference).getParent() instanceof GrUnaryExpression &&
|
||||
((GrUnaryExpression)((GrReferenceExpression)reference).getParent()).isPostfix())) {
|
||||
if (hasAssignment) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+6
@@ -35,6 +35,8 @@ groovy.dfa.issues=Data Flow Issues
|
||||
unused.assignment=Unused Assignment
|
||||
unused.assignment.tooltip=Assignment is not used
|
||||
|
||||
unused.inc.dec=Unused Incrementing or Decrementing
|
||||
|
||||
unassigned.access=Variable Not Assigned
|
||||
unassigned.access.short.name=VariableNotAssigned
|
||||
unassigned.access.tooltip=Variable ''{0}'' might not be assigned
|
||||
@@ -77,3 +79,7 @@ rtype.cannot.contain.ltype=''{1}'' cannot contain ''{0}''
|
||||
new.instance.of.singleton=New instance of class annotated with @groovy.lang.Singleton
|
||||
replace.new.expression.with.0.instance=Replace with ''{0}.instance''
|
||||
getter.0.clashes.with.getter.1={0} clashes with {1}
|
||||
unused.0=Unused {0}
|
||||
remove.0=Remove {0}
|
||||
replace.postfix.0.with.prefix.0=Replace postfix {0} with prefix {0}
|
||||
replace.0.with.1=Replace {0} with binary {1}
|
||||
|
||||
+6
-1
@@ -22,6 +22,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
@@ -42,7 +43,6 @@ public abstract class GroovyLocalInspectionBase extends GroovySuppressableInspec
|
||||
return new GroovyPsiElementVisitor(new GroovyElementVisitor() {
|
||||
public void visitClosure(GrClosableBlock closure) {
|
||||
check(closure, problemsHolder);
|
||||
|
||||
}
|
||||
|
||||
public void visitMethod(GrMethod method) {
|
||||
@@ -55,6 +55,11 @@ public abstract class GroovyLocalInspectionBase extends GroovySuppressableInspec
|
||||
public void visitFile(GroovyFileBase file) {
|
||||
check(file, problemsHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassInitializer(GrClassInitializer initializer) {
|
||||
check(initializer.getBlock(), problemsHolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.codeInspection.confusing;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.BaseInspection;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class GrUnusedIncDecInspection extends BaseInspection {
|
||||
private static final Logger LOG = Logger.getInstance(GrUnusedIncDecInspection.class);
|
||||
@Override
|
||||
protected BaseInspectionVisitor buildVisitor() {
|
||||
return new GrUnusedIncDecInspectionVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return GroovyInspectionBundle.message("groovy.dfa.issues");
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return GroovyInspectionBundle.message("unused.inc.dec");
|
||||
}
|
||||
|
||||
@NonNls
|
||||
@NotNull
|
||||
public String getShortName() {
|
||||
return "GroovyUnusedIncOrDec";
|
||||
}
|
||||
|
||||
private static class GrUnusedIncDecInspectionVisitor extends BaseInspectionVisitor {
|
||||
@Override
|
||||
public void visitUnaryExpression(GrUnaryExpression expression) {
|
||||
super.visitUnaryExpression(expression);
|
||||
|
||||
IElementType opType = expression.getOperationTokenType();
|
||||
if (opType != GroovyTokenTypes.mINC && opType != GroovyTokenTypes.mDEC) return;
|
||||
|
||||
GrExpression operand = expression.getOperand();
|
||||
if (!(operand instanceof GrReferenceExpression)) return;
|
||||
|
||||
PsiElement resolved = ((GrReferenceExpression)operand).resolve();
|
||||
if (!(resolved instanceof GrVariable) || resolved instanceof GrField) return;
|
||||
|
||||
final GrControlFlowOwner owner = ControlFlowUtils.findControlFlowOwner(expression);
|
||||
assert owner != null;
|
||||
GrControlFlowOwner ownerOfDeclaration = ControlFlowUtils.findControlFlowOwner(resolved);
|
||||
if (ownerOfDeclaration != owner) return;
|
||||
|
||||
final Instruction cur = ControlFlowUtils.findInstruction(operand, owner.getControlFlow());
|
||||
|
||||
if (cur == null) {
|
||||
LOG.error("no instruction found in flow." + "operand: " + operand.getText() + " cfo: " + owner.getText());
|
||||
}
|
||||
|
||||
//get write access for inc or dec
|
||||
Iterable<? extends Instruction> successors = cur.allSuccessors();
|
||||
Iterator<? extends Instruction> iterator = successors.iterator();
|
||||
LOG.assertTrue(iterator.hasNext());
|
||||
Instruction writeAccess = iterator.next();
|
||||
LOG.assertTrue(!iterator.hasNext());
|
||||
|
||||
List<ReadWriteVariableInstruction> accesses = ControlFlowUtils.findAccess((GrVariable)resolved, true, false, writeAccess);
|
||||
|
||||
boolean allAreWrite = true;
|
||||
for (ReadWriteVariableInstruction access : accesses) {
|
||||
if (!access.isWrite()) {
|
||||
allAreWrite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (allAreWrite) {
|
||||
if (expression.isPostfix() && PsiUtil.isExpressionUsed(expression)) {
|
||||
registerError(expression.getOperationToken(),
|
||||
GroovyInspectionBundle.message("unused.0", expression.getOperationToken().getText()),
|
||||
new LocalQuickFix[]{new ReplacePostfixIncWithPrefixFix(expression), new RemoveIncOrDecFix(expression)},
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL);
|
||||
}
|
||||
else if (!PsiUtil.isExpressionUsed(expression)) {
|
||||
registerError(expression.getOperationToken(),
|
||||
GroovyInspectionBundle.message("unused.0", expression.getOperationToken().getText()), LocalQuickFix.EMPTY_ARRAY,
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class RemoveIncOrDecFix implements LocalQuickFix {
|
||||
private final String myMessage;
|
||||
|
||||
public RemoveIncOrDecFix(GrUnaryExpression expression) {
|
||||
myMessage = GroovyInspectionBundle.message("remove.0", expression.getOperationToken().getText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
GrUnaryExpression expr = findUnaryExpression(descriptor);
|
||||
if (expr == null) return;
|
||||
|
||||
expr.replaceWithExpression(expr.getOperand(), true);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplacePostfixIncWithPrefixFix implements LocalQuickFix {
|
||||
private final String myMessage;
|
||||
|
||||
public ReplacePostfixIncWithPrefixFix(GrUnaryExpression expression) {
|
||||
myMessage = GroovyInspectionBundle.message("replace.postfix.0.with.prefix.0", expression.getOperationToken().getText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
GrUnaryExpression expr = findUnaryExpression(descriptor);
|
||||
if (expr == null) return;
|
||||
|
||||
GrExpression prefix = GroovyPsiElementFactory.getInstance(project)
|
||||
.createExpressionFromText(expr.getOperationToken().getText() + expr.getOperand().getText());
|
||||
|
||||
expr.replaceWithExpression(prefix, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplaceIncDecWithBinary implements LocalQuickFix {
|
||||
private final String myMessage;
|
||||
|
||||
public ReplaceIncDecWithBinary(GrUnaryExpression expression) {
|
||||
String opToken = expression.getOperationToken().getText();
|
||||
myMessage = GroovyInspectionBundle.message("replace.0.with.1", opToken, opToken.substring(0, 1));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
GrUnaryExpression expr = findUnaryExpression(descriptor);
|
||||
GrExpression newExpr = GroovyPsiElementFactory.getInstance(project)
|
||||
.createExpressionFromText(expr.getOperand().getText() + expr.getOperationToken().getText().substring(0, 1) + "1");
|
||||
expr.replaceWithExpression(newExpr, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static GrUnaryExpression findUnaryExpression(ProblemDescriptor descriptor) {
|
||||
GrUnaryExpression expr;
|
||||
PsiElement element = descriptor.getPsiElement();
|
||||
if (element == null) return null;
|
||||
PsiElement parent = element.getParent();
|
||||
IElementType opType = element.getNode().getElementType();
|
||||
if (opType != GroovyTokenTypes.mINC && opType != GroovyTokenTypes.mDEC) return null;
|
||||
if (!(parent instanceof GrUnaryExpression)) return null;
|
||||
expr = (GrUnaryExpression)parent;
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -30,7 +30,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrBlockStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrWhileStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -94,9 +97,8 @@ public class GroovyWhileLoopSpinsOnFieldInspection extends BaseInspection {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (condition instanceof GrPostfixExpression) {
|
||||
final GrPostfixExpression postfixExpression =
|
||||
(GrPostfixExpression) condition;
|
||||
if (condition instanceof GrUnaryExpression && ((GrUnaryExpression)condition).isPostfix()) {
|
||||
final GrUnaryExpression postfixExpression = (GrUnaryExpression) condition;
|
||||
final GrExpression operand =
|
||||
postfixExpression.getOperand();
|
||||
return isSimpleFieldComparison(operand);
|
||||
|
||||
+51
-43
@@ -24,7 +24,7 @@ import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.impl.DebugUtil;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.Processor;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
@@ -33,28 +33,25 @@ import gnu.trove.TObjectProcedure;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.GroovyLocalInspectionBase;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsDfaInstance;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsSemilattice;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
& @author ven
|
||||
@@ -86,7 +83,7 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase {
|
||||
final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow);
|
||||
final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice();
|
||||
final DFAEngine<TIntObjectHashMap<TIntHashSet>> engine = new DFAEngine<TIntObjectHashMap<TIntHashSet>>(flow, dfaInstance, lattice);
|
||||
final ArrayList<TIntObjectHashMap<TIntHashSet>> dfaResult = engine.performDFA();
|
||||
final List<TIntObjectHashMap<TIntHashSet>> dfaResult = engine.performDFA();
|
||||
final TIntHashSet unusedDefs = new TIntHashSet();
|
||||
for (Instruction instruction : flow) {
|
||||
if (instruction instanceof ReadWriteVariableInstruction && ((ReadWriteVariableInstruction) instruction).isWrite()) {
|
||||
@@ -97,9 +94,9 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase {
|
||||
for (int i = 0; i < dfaResult.size(); i++) {
|
||||
final Instruction instruction = flow[i];
|
||||
if (instruction instanceof ReadWriteVariableInstruction) {
|
||||
final ReadWriteVariableInstruction varInsn = (ReadWriteVariableInstruction) instruction;
|
||||
if (!varInsn.isWrite()) {
|
||||
final String varName = varInsn.getVariableName();
|
||||
final ReadWriteVariableInstruction varInst = (ReadWriteVariableInstruction) instruction;
|
||||
if (!varInst.isWrite()) {
|
||||
final String varName = varInst.getVariableName();
|
||||
TIntObjectHashMap<TIntHashSet> e = dfaResult.get(i);
|
||||
e.forEachValue(new TObjectProcedure<TIntHashSet>() {
|
||||
public boolean execute(TIntHashSet reaching) {
|
||||
@@ -124,21 +121,8 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase {
|
||||
final ReadWriteVariableInstruction instruction = (ReadWriteVariableInstruction)flow[num];
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (element == null) return true;
|
||||
PsiElement toHighlight = null;
|
||||
if (isLocalAssignment(element) && isUsedInToplevelFlowOnly(element)) {
|
||||
if (element instanceof GrReferenceExpression) {
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof GrAssignmentExpression) {
|
||||
toHighlight = ((GrAssignmentExpression)parent).getLValue();
|
||||
}
|
||||
if (parent instanceof GrPostfixExpression) {
|
||||
toHighlight = parent;
|
||||
}
|
||||
}
|
||||
else if (element instanceof GrVariable) {
|
||||
toHighlight = ((GrVariable)element).getNameIdentifierGroovy();
|
||||
}
|
||||
if (toHighlight == null) toHighlight = element;
|
||||
if (isLocalAssignment(element) && isUsedInTopLevelFlowOnly(element) && !isIncOrDec(element)) {
|
||||
PsiElement toHighlight = getHighlightElement(element);
|
||||
problemsHolder.registerProblem(toHighlight, GroovyInspectionBundle.message("unused.assignment.tooltip"),
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL);
|
||||
}
|
||||
@@ -147,25 +131,52 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase {
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isUsedInToplevelFlowOnly(PsiElement element) {
|
||||
private static PsiElement getHighlightElement(PsiElement element) {
|
||||
PsiElement toHighlight = null;
|
||||
if (element instanceof GrReferenceExpression) {
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof GrAssignmentExpression) {
|
||||
toHighlight = ((GrAssignmentExpression)parent).getLValue();
|
||||
}
|
||||
if (parent instanceof GrUnaryExpression && ((GrUnaryExpression)parent).isPostfix()) {
|
||||
toHighlight = parent;
|
||||
}
|
||||
}
|
||||
else if (element instanceof GrVariable) {
|
||||
toHighlight = ((GrVariable)element).getNameIdentifierGroovy();
|
||||
}
|
||||
if (toHighlight == null) toHighlight = element;
|
||||
return toHighlight;
|
||||
}
|
||||
|
||||
private static boolean isIncOrDec(PsiElement element) {
|
||||
PsiElement parent = element.getParent();
|
||||
if (!(parent instanceof GrUnaryExpression)) return false;
|
||||
|
||||
IElementType type = ((GrUnaryExpression)parent).getOperationTokenType();
|
||||
return type == GroovyTokenTypes.mINC || type == GroovyTokenTypes.mDEC;
|
||||
}
|
||||
|
||||
private static boolean isUsedInTopLevelFlowOnly(PsiElement element) {
|
||||
GrVariable var = null;
|
||||
if (element instanceof GrVariable) {
|
||||
var = (GrVariable) element;
|
||||
} else if (element instanceof GrReferenceExpression) {
|
||||
final PsiElement resolved = ((GrReferenceExpression) element).resolve();
|
||||
if (resolved instanceof GrVariable) var = (GrVariable) resolved;
|
||||
var = (GrVariable)element;
|
||||
}
|
||||
else if (element instanceof GrReferenceExpression) {
|
||||
final PsiElement resolved = ((GrReferenceExpression)element).resolve();
|
||||
if (resolved instanceof GrVariable) var = (GrVariable)resolved;
|
||||
}
|
||||
|
||||
if (var != null) {
|
||||
final GroovyPsiElement scope = getScope(var);
|
||||
final GroovyPsiElement scope = ControlFlowUtils.findControlFlowOwner(var);
|
||||
if (scope == null) {
|
||||
PsiFile file = var.getContainingFile();
|
||||
LOG.error(file == null ? "no file??? var of type"+ var.getClass().getCanonicalName() : DebugUtil.psiToString(file, true, false));
|
||||
LOG.error(file == null ? "no file??? var of type" + var.getClass().getCanonicalName() : DebugUtil.psiToString(file, true, false));
|
||||
}
|
||||
|
||||
return ReferencesSearch.search(var, new LocalSearchScope(scope)).forEach(new Processor<PsiReference>() {
|
||||
public boolean process(PsiReference ref) {
|
||||
return getScope(ref.getElement()) == scope;
|
||||
return ControlFlowUtils.findControlFlowOwner(ref.getElement()) == scope;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -173,17 +184,14 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static GroovyPsiElement getScope(PsiElement var) {
|
||||
return PsiTreeUtil.getContextOfType(var, GrClosableBlock.class, GrMethod.class, GrClassInitializer.class, GroovyFileBase.class);
|
||||
}
|
||||
|
||||
private static boolean isLocalAssignment(PsiElement element) {
|
||||
if (element instanceof GrVariable) {
|
||||
return isLocalVariable((GrVariable) element, false);
|
||||
} else if (element instanceof GrReferenceExpression) {
|
||||
final PsiElement resolved = ((GrReferenceExpression) element).resolve();
|
||||
return resolved instanceof GrVariable && isLocalVariable((GrVariable) resolved, true);
|
||||
return isLocalVariable((GrVariable)element, false);
|
||||
}
|
||||
else if (element instanceof GrReferenceExpression) {
|
||||
final PsiElement resolved = ((GrReferenceExpression)element).resolve();
|
||||
return resolved instanceof GrVariable && isLocalVariable((GrVariable)resolved, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
+19
-16
@@ -40,7 +40,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnState
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
@@ -54,7 +53,6 @@ import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DfaInstance;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.Semilattice;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -499,7 +497,6 @@ public class ControlFlowUtils {
|
||||
|
||||
public static boolean isIncOrDecOperand(GrReferenceExpression referenceExpression) {
|
||||
final PsiElement parent = referenceExpression.getParent();
|
||||
if (parent instanceof GrPostfixExpression) return true;
|
||||
if (parent instanceof GrUnaryExpression) {
|
||||
final IElementType opType = ((GrUnaryExpression)parent).getOperationTokenType();
|
||||
return opType == GroovyTokenTypes.mDEC || opType == GroovyTokenTypes.mINC;
|
||||
@@ -650,10 +647,10 @@ public class ControlFlowUtils {
|
||||
@Nullable
|
||||
public static GrControlFlowOwner findControlFlowOwner(PsiElement place) {
|
||||
if (place instanceof GrCodeBlock) {
|
||||
place = place.getParent();
|
||||
place = place.getContext();
|
||||
}
|
||||
while (true) {
|
||||
place = place.getParent();
|
||||
place = place.getContext();
|
||||
if (place == null) return null;
|
||||
if (place instanceof GrClosableBlock) return (GrClosableBlock)place;
|
||||
if (place instanceof GrMethod) return ((GrMethod)place).getBlock();
|
||||
@@ -675,22 +672,28 @@ public class ControlFlowUtils {
|
||||
}
|
||||
|
||||
public static List<ReadWriteVariableInstruction> findAccess(GrVariable local, final PsiElement place, boolean ahead, boolean writeAccessOnly) {
|
||||
LOG.assertTrue(GroovyRefactoringUtil.isLocalVariable(local), local.getClass());
|
||||
LOG.assertTrue(!(local instanceof GrField), local.getClass());
|
||||
|
||||
final GrControlFlowOwner owner = findControlFlowOwner(local);
|
||||
assert owner != null;
|
||||
|
||||
final Instruction cur = findInstruction(place, owner.getControlFlow());
|
||||
|
||||
if (cur == null) throw new IllegalArgumentException("place is not in the flow");
|
||||
if (cur == null) {
|
||||
throw new IllegalArgumentException("place is not in the flow");
|
||||
}
|
||||
|
||||
return findAccess(local, ahead, writeAccessOnly, cur);
|
||||
}
|
||||
|
||||
public static List<ReadWriteVariableInstruction> findAccess(GrVariable local, boolean ahead, boolean writeAccessOnly, Instruction cur) {
|
||||
String name = local.getName();
|
||||
|
||||
|
||||
final ArrayList<ReadWriteVariableInstruction> result = new ArrayList<ReadWriteVariableInstruction>();
|
||||
final HashSet<Instruction> visited = new HashSet<Instruction>();
|
||||
|
||||
|
||||
visited.add(cur);
|
||||
|
||||
|
||||
Queue<Instruction> queue = new ArrayDeque<Instruction>();
|
||||
|
||||
for (Instruction i : ahead ? cur.allSuccessors() : cur.allPredecessors()) {
|
||||
@@ -698,11 +701,11 @@ public class ControlFlowUtils {
|
||||
queue.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (true) {
|
||||
Instruction instruction = queue.poll();
|
||||
if (instruction == null) break;
|
||||
|
||||
|
||||
if (instruction instanceof ReadWriteVariableInstruction) {
|
||||
ReadWriteVariableInstruction rw = (ReadWriteVariableInstruction)instruction;
|
||||
if (name.equals(rw.getVariableName())) {
|
||||
@@ -710,13 +713,13 @@ public class ControlFlowUtils {
|
||||
result.add(rw);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!writeAccessOnly) {
|
||||
result.add(rw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (Instruction i : ahead ? instruction.allSuccessors() : instruction.allPredecessors()) {
|
||||
if (visited.add(i)) {
|
||||
queue.add(i);
|
||||
@@ -726,9 +729,9 @@ public class ControlFlowUtils {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static Instruction findInstruction(final PsiElement place, Instruction[] controlFlow) {
|
||||
public static Instruction findInstruction(final PsiElement place, Instruction[] controlFlow) {
|
||||
return ContainerUtil.find(controlFlow, new Condition<Instruction>() {
|
||||
@Override
|
||||
public boolean value(Instruction instruction) {
|
||||
|
||||
+6
-9
@@ -445,8 +445,8 @@ public class EquivalenceChecker {
|
||||
return prefixExpressionsAreEquivalent((GrUnaryExpression) expToCompare1,
|
||||
(GrUnaryExpression) expToCompare2);
|
||||
case POSTFIX_EXPRESSION:
|
||||
return postfixExpressionsAreEquivalent((GrPostfixExpression) expToCompare1,
|
||||
(GrPostfixExpression) expToCompare2);
|
||||
return postfixExpressionsAreEquivalent((GrUnaryExpression) expToCompare1,
|
||||
(GrUnaryExpression) expToCompare2);
|
||||
case BINARY_EXPRESSION:
|
||||
return binaryExpressionsAreEquivalent((GrBinaryExpression) expToCompare1,
|
||||
(GrBinaryExpression) expToCompare2);
|
||||
@@ -674,8 +674,8 @@ public class EquivalenceChecker {
|
||||
return expressionsAreEquivalent(operand1, operand2);
|
||||
}
|
||||
|
||||
private static boolean postfixExpressionsAreEquivalent(@NotNull GrPostfixExpression postfixExp1,
|
||||
@NotNull GrPostfixExpression postfixExp2) {
|
||||
private static boolean postfixExpressionsAreEquivalent(@NotNull GrUnaryExpression postfixExp1,
|
||||
@NotNull GrUnaryExpression postfixExp2) {
|
||||
final IElementType sign1 = postfixExp1.getOperationTokenType();
|
||||
final IElementType sign2 = postfixExp2.getOperationTokenType();
|
||||
if (!sign1.equals(sign2)) {
|
||||
@@ -690,7 +690,7 @@ public class EquivalenceChecker {
|
||||
@NotNull GrBinaryExpression binaryExp2) {
|
||||
final IElementType sign1 = binaryExp1.getOperationTokenType();
|
||||
final IElementType sign2 = binaryExp2.getOperationTokenType();
|
||||
if (sign1 == null || sign2 == null || !sign1.equals(sign2)) {
|
||||
if (!sign1.equals(sign2)) {
|
||||
return false;
|
||||
}
|
||||
final GrExpression lhs1 = binaryExp1.getLeftOperand();
|
||||
@@ -834,11 +834,8 @@ public class EquivalenceChecker {
|
||||
if (exp instanceof GrMethodCall) {
|
||||
return CALL_EXPRESSION;
|
||||
}
|
||||
if (exp instanceof GrPostfixExpression) {
|
||||
return POSTFIX_EXPRESSION;
|
||||
}
|
||||
if (exp instanceof GrUnaryExpression) {
|
||||
return PREFIX_EXPRESSION;
|
||||
return ((GrUnaryExpression)exp).isPostfix() ? POSTFIX_EXPRESSION : PREFIX_EXPRESSION;
|
||||
}
|
||||
if (exp instanceof GrAssignmentExpression) {
|
||||
return ASSIGNMENT_EXPRESSION;
|
||||
|
||||
+4
-14
@@ -20,7 +20,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
|
||||
|
||||
public class SideEffectChecker {
|
||||
@@ -71,19 +74,6 @@ public class SideEffectChecker {
|
||||
mayHaveSideEffects = true;
|
||||
}
|
||||
|
||||
public void visitPostfixExpression(
|
||||
@NotNull GrPostfixExpression expression) {
|
||||
if (mayHaveSideEffects) {
|
||||
return;
|
||||
}
|
||||
super.visitPostfixExpression(expression);
|
||||
final IElementType tokenType = expression.getOperationTokenType();
|
||||
if (tokenType.equals(GroovyTokenTypes.mINC) ||
|
||||
tokenType.equals(GroovyTokenTypes.mDEC)) {
|
||||
mayHaveSideEffects = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void visitUnaryExpression(
|
||||
@NotNull GrUnaryExpression expression) {
|
||||
if (mayHaveSideEffects) {
|
||||
|
||||
@@ -165,38 +165,40 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
|
||||
|
||||
parameters.setMainClass(GroovycRunner.class.getName());
|
||||
|
||||
try {
|
||||
final VirtualFile finalOutputDir = getMainOutput(compileContext, module, tests);
|
||||
LOG.assertTrue(finalOutputDir != null, "No output directory for module " + module.getName() + (tests ? " tests" : " production"));
|
||||
final Charset ideCharset = EncodingProjectManager.getInstance(myProject).getDefaultCharset();
|
||||
String encoding = ideCharset != null && !Comparing.equal(CharsetToolkit.getDefaultSystemCharset(), ideCharset) ? ideCharset.name() : null;
|
||||
Set<String> paths2Compile = ContainerUtil.map2Set(toCompile, new Function<VirtualFile, String>() {
|
||||
@Override
|
||||
public String fun(VirtualFile file) {
|
||||
return file.getPath();
|
||||
}
|
||||
});
|
||||
Map<String, String> class2Src = new HashMap<String, String>();
|
||||
final VirtualFile finalOutputDir = getMainOutput(compileContext, module, tests);
|
||||
LOG.assertTrue(finalOutputDir != null, "No output directory for module " + module.getName() + (tests ? " tests" : " production"));
|
||||
final Charset ideCharset = EncodingProjectManager.getInstance(myProject).getDefaultCharset();
|
||||
String encoding = ideCharset != null && !Comparing.equal(CharsetToolkit.getDefaultSystemCharset(), ideCharset) ? ideCharset.name() : null;
|
||||
Set<String> paths2Compile = ContainerUtil.map2Set(toCompile, new Function<VirtualFile, String>() {
|
||||
@Override
|
||||
public String fun(VirtualFile file) {
|
||||
return file.getPath();
|
||||
}
|
||||
});
|
||||
Map<String, String> class2Src = new HashMap<String, String>();
|
||||
|
||||
for (VirtualFile file : enumerateGroovyFiles(module)) {
|
||||
if (!paths2Compile.contains(file.getPath())) {
|
||||
for (String name : TranslatingCompilerFilesMonitor.getInstance().getCompiledClassNames(file, myProject)) {
|
||||
class2Src.put(name, file.getPath());
|
||||
}
|
||||
for (VirtualFile file : enumerateGroovyFiles(module)) {
|
||||
if (!paths2Compile.contains(file.getPath())) {
|
||||
for (String name : TranslatingCompilerFilesMonitor.getInstance().getCompiledClassNames(file, myProject)) {
|
||||
class2Src.put(name, file.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File fileWithParameters = GroovycOSProcessHandler
|
||||
final File fileWithParameters;
|
||||
try {
|
||||
fileWithParameters = GroovycOSProcessHandler
|
||||
.fillFileWithGroovycParameters(outputDir.getPath(), paths2Compile, FileUtil.toSystemDependentName(finalOutputDir.getPath()),
|
||||
class2Src, encoding, patchers);
|
||||
|
||||
parameters.getProgramParametersList().add(forStubs ? "stubs" : "groovyc");
|
||||
parameters.getProgramParametersList().add(fileWithParameters.getPath());
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
LOG.info(e);
|
||||
compileContext.addMessage(CompilerMessageCategory.ERROR, "Error creating a temp file to launch Groovy compiler: " + e.getMessage(), null, -1, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
parameters.getProgramParametersList().add(forStubs ? "stubs" : "groovyc");
|
||||
parameters.getProgramParametersList().add(fileWithParameters.getPath());
|
||||
|
||||
try {
|
||||
Process process = JdkUtil.setupJVMCommandLine(exePath, parameters, true).createProcess();
|
||||
@@ -272,7 +274,8 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
|
||||
sink.add(outputDir.getPath(), items, VfsUtil.toVirtualFileArray(toRecompile));
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
LOG.info(e);
|
||||
compileContext.addMessage(CompilerMessageCategory.ERROR, "Error running Groovy compiler: " + e.getMessage(), null, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-11
@@ -484,17 +484,8 @@ public class GroovySpacingProcessor extends GroovyElementVisitor {
|
||||
|
||||
@Override
|
||||
public void visitUnaryExpression(GrUnaryExpression expression) {
|
||||
//prefix only
|
||||
LOG.assertTrue(!(expression instanceof GrPostfixExpression));
|
||||
|
||||
if (expression.getOperationToken() == myChild1) {
|
||||
createSpaceInCode(mySettings.SPACE_AROUND_UNARY_OPERATOR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPostfixExpression(GrPostfixExpression expression) {
|
||||
if (expression.getOperationToken() == myChild2) {
|
||||
if (!expression.isPostfix() && expression.getOperationToken() == myChild1 ||
|
||||
expression.isPostfix() && expression.getOperationToken() == myChild2) {
|
||||
createSpaceInCode(mySettings.SPACE_AROUND_UNARY_OPERATOR);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -104,17 +104,14 @@ public class ParenthesesUtils {
|
||||
expression instanceof GrNewExpression) {
|
||||
return TYPE_CAST_PRECEDENCE;
|
||||
}
|
||||
if (expression instanceof GrPostfixExpression) {
|
||||
return POSTFIX_PRECEDENCE;
|
||||
}
|
||||
if (expression instanceof GrUnaryExpression) {
|
||||
return PREFIX_PRECEDENCE;
|
||||
return ((GrUnaryExpression)expression).isPostfix()?POSTFIX_PRECEDENCE:PREFIX_PRECEDENCE;
|
||||
}
|
||||
if (expression instanceof GrBinaryExpression) {
|
||||
final GrBinaryExpression binaryExpression =
|
||||
(GrBinaryExpression) expression;
|
||||
final IElementType sign = binaryExpression.getOperationTokenType();
|
||||
if (sign != null) return precedenceForBinaryOperator(sign);
|
||||
return precedenceForBinaryOperator(sign);
|
||||
}
|
||||
if (expression instanceof GrConditionalExpression) {
|
||||
return CONDITIONAL_PRECEDENCE;
|
||||
|
||||
@@ -201,14 +201,4 @@ public abstract class TokenSets {
|
||||
);
|
||||
|
||||
public static final TokenSet SHIFT_SIGNS = TokenSet.create(COMPOSITE_LSHIFT_SIGN, COMPOSITE_RSHIFT_SIGN, COMPOSITE_TRIPLE_SHIFT_SIGN);
|
||||
|
||||
public static final TokenSet POSTFIXES = TokenSet.create(mINC,mDEC);
|
||||
public static final TokenSet PREFIXES = TokenSet.create(
|
||||
mPLUS,
|
||||
mMINUS,
|
||||
mINC,
|
||||
mDEC,
|
||||
mBNOT,
|
||||
mLNOT
|
||||
);
|
||||
}
|
||||
|
||||
@@ -222,7 +222,6 @@ public interface GroovyElementTypes extends GroovyTokenTypes, GroovyDocElementTy
|
||||
GroovyElementType CAST_EXPRESSION = new GroovyElementType("cast expression");
|
||||
GroovyElementType SAFE_CAST_EXPRESSION = new GroovyElementType("safe cast expression");
|
||||
GroovyElementType INSTANCEOF_EXPRESSION = new GroovyElementType("instanceof expression");
|
||||
GroovyElementType POSTFIX_EXPRESSION = new GroovyElementType("Postfix expression");
|
||||
GroovyElementType PATH_PROPERTY_REFERENCE = new GroovyElementType("Property reference");
|
||||
|
||||
GroovyElementType PATH_METHOD_CALL = new GroovyElementType("Method call");
|
||||
|
||||
@@ -28,7 +28,10 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyASTPsiElementImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrLabelImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrListOrMapImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrThrowsClauseImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationArgumentListImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationArrrayInitializerImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationNameValuePairImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrModifierListImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.arguments.GrArgumentLabelImpl;
|
||||
@@ -218,7 +221,6 @@ public class GroovyPsiCreator implements GroovyElementTypes {
|
||||
if (elem == POWER_EXPRESSION) return new GrPowerExpressionImpl(node);
|
||||
if (elem == POWER_EXPRESSION_SIMPLE) return new GrPowerExpressionImpl(node);
|
||||
if (elem == UNARY_EXPRESSION) return new GrUnaryExpressionImpl(node);
|
||||
if (elem == POSTFIX_EXPRESSION) return new GrPostfixExprImpl(node);
|
||||
if (elem == CAST_EXPRESSION) return new GrTypeCastExpressionImpl(node);
|
||||
if (elem == SAFE_CAST_EXPRESSION) return new GrSafeCastExpressionImpl(node);
|
||||
if (elem == INSTANCEOF_EXPRESSION) return new GrInstanceofExpressionImpl(node);
|
||||
|
||||
+2
-2
@@ -40,9 +40,9 @@ public class PostfixExpression implements GroovyElementTypes {
|
||||
}
|
||||
|
||||
private static void subParse(PsiBuilder builder, PsiBuilder.Marker marker) {
|
||||
if (ParserUtils.getToken(builder, TokenSets.POSTFIXES)) {
|
||||
if (ParserUtils.getToken(builder, TokenSets.POSTFIX_UNARY_OP_SET)) {
|
||||
PsiBuilder.Marker newMarker = marker.precede();
|
||||
marker.done(POSTFIX_EXPRESSION);
|
||||
marker.done(UNARY_EXPRESSION);
|
||||
subParse(builder, newMarker);
|
||||
}
|
||||
else {
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ public class UnaryExpression implements GroovyElementTypes {
|
||||
|
||||
public static boolean parse(PsiBuilder builder, GroovyParser parser) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
if (ParserUtils.getToken(builder, TokenSets.PREFIXES)) {
|
||||
if (ParserUtils.getToken(builder, TokenSets.UNARY_OP_SET)) {
|
||||
ParserUtils.getToken(builder, mNLS);
|
||||
parse(builder, parser);
|
||||
marker.done(UNARY_EXPRESSION);
|
||||
|
||||
@@ -168,10 +168,6 @@ public abstract class GroovyElementVisitor {
|
||||
visitExpression(expression);
|
||||
}
|
||||
|
||||
public void visitPostfixExpression(GrPostfixExpression expression) {
|
||||
visitUnaryExpression(expression);
|
||||
}
|
||||
|
||||
public void visitRegexExpression(GrRegex expression) {
|
||||
visitGStringExpression(expression);
|
||||
}
|
||||
@@ -443,4 +439,8 @@ public abstract class GroovyElementVisitor {
|
||||
public void visitTypeParameterList(GrTypeParameterList list) {
|
||||
visitElement(list);
|
||||
}
|
||||
|
||||
public void visitClassInitializer(GrClassInitializer initializer) {
|
||||
visitElement(initializer);
|
||||
}
|
||||
}
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
*/
|
||||
public interface GrPostfixExpression extends GrUnaryExpression {
|
||||
}
|
||||
+2
@@ -35,4 +35,6 @@ public interface GrUnaryExpression extends GrExpression, PsiPolyVariantReference
|
||||
@NotNull
|
||||
@Override
|
||||
GroovyResolveResult[] multiResolve(final boolean incompleteCode);
|
||||
|
||||
boolean isPostfix();
|
||||
}
|
||||
|
||||
+5
-2
@@ -23,13 +23,16 @@ import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl;
|
||||
* @author ven
|
||||
*/
|
||||
public class ReadWriteVariableInstruction extends InstructionImpl {
|
||||
public static final int WRITE = -1;
|
||||
public static final int READ = 1;
|
||||
|
||||
private final boolean myIsWrite;
|
||||
private final String myName;
|
||||
|
||||
public ReadWriteVariableInstruction(@NotNull String varName, PsiElement element, int num, boolean isWrite) {
|
||||
public ReadWriteVariableInstruction(@NotNull String varName, PsiElement element, int num, int accessType) {
|
||||
super(element, num);
|
||||
myName = varName;
|
||||
myIsWrite = isWrite;
|
||||
myIsWrite = accessType == WRITE;
|
||||
}
|
||||
|
||||
@NotNull public String getVariableName() {
|
||||
|
||||
+95
-25
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.hash.HashSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
@@ -51,6 +52,9 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction.READ;
|
||||
import static org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction.WRITE;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
@@ -107,7 +111,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
final PsiElement lbrace = block.getLBrace();
|
||||
if (lbrace != null && parent instanceof GrMethod) {
|
||||
for (GrParameter parameter : ((GrMethod)parent).getParameters()) {
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, true));
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, WRITE));
|
||||
}
|
||||
}
|
||||
super.visitOpenBlock(block);
|
||||
@@ -185,7 +189,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
|
||||
private void buildFlowForClosure(final GrClosableBlock closure) {
|
||||
for (GrParameter parameter : closure.getAllParameters()) {
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, true));
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, WRITE));
|
||||
}
|
||||
|
||||
final Set<String> names = new LinkedHashSet<String>();
|
||||
@@ -207,7 +211,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
names.add("owner");
|
||||
|
||||
for (String name : names) {
|
||||
addNode(new ReadWriteVariableInstruction(name, closure.getLBrace(), myInstructionNumber++, true));
|
||||
addNode(new ReadWriteVariableInstruction(name, closure.getLBrace(), myInstructionNumber++, WRITE));
|
||||
}
|
||||
|
||||
PsiElement child = closure.getFirstChild();
|
||||
@@ -241,12 +245,26 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
//do not go inside closures except gstring injections
|
||||
if (closure.getParent() instanceof GrStringInjection) {
|
||||
super.visitClosure(closure);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//create instruction for closure to use it in inline local refactoring
|
||||
final InstructionImpl i = new InstructionImpl(closure, myInstructionNumber++);
|
||||
|
||||
Set<String> names = new HashSet<String>();
|
||||
|
||||
ReadWriteVariableInstruction[] reads = ControlFlowBuilderUtil.getReadsWithoutPriorWrites(closure.getControlFlow());
|
||||
for (ReadWriteVariableInstruction read : reads) {
|
||||
names.add(read.getVariableName());
|
||||
}
|
||||
|
||||
for (String name : names) {
|
||||
ReadWriteVariableInstruction i = new ReadWriteVariableInstruction(name, closure, myInstructionNumber++, READ);
|
||||
addNode(i);
|
||||
checkPending(i);
|
||||
}
|
||||
|
||||
|
||||
InstructionImpl i = new InstructionImpl(closure, myInstructionNumber++);
|
||||
addNode(i);
|
||||
checkPending(i);
|
||||
}
|
||||
|
||||
public void visitBreakStatement(GrBreakStatement breakStatement) {
|
||||
@@ -364,7 +382,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
if (lValue instanceof GrReferenceExpression) {
|
||||
String referenceName = ((GrReferenceExpression)lValue).getReferenceName();
|
||||
if (referenceName != null) {
|
||||
ReadWriteVariableInstruction instruction = new ReadWriteVariableInstruction(referenceName, lValue, myInstructionNumber++, false);
|
||||
ReadWriteVariableInstruction instruction = new ReadWriteVariableInstruction(referenceName, lValue, myInstructionNumber++, READ);
|
||||
addNode(instruction);
|
||||
checkPending(instruction);
|
||||
}
|
||||
@@ -413,17 +431,14 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
if (name == null) return;
|
||||
|
||||
if (ControlFlowUtils.isIncOrDecOperand(refExpr) && !myAssertionsOnly) {
|
||||
final ReadWriteVariableInstruction i = new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, false);
|
||||
final InstructionImpl i = new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, READ);
|
||||
addNode(i);
|
||||
addNode(new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, true));
|
||||
if (refExpr.getParent() instanceof GrUnaryExpression) {
|
||||
addNode(new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, false));
|
||||
}
|
||||
addNode(new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, WRITE));
|
||||
checkPending(i);
|
||||
}
|
||||
else {
|
||||
final ReadWriteVariableInstruction i =
|
||||
new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, !myAssertionsOnly && PsiUtil.isLValue(refExpr));
|
||||
boolean isWrite = !myAssertionsOnly && PsiUtil.isLValue(refExpr);
|
||||
final InstructionImpl i = new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, isWrite ? WRITE : READ);
|
||||
addNode(i);
|
||||
checkPending(i);
|
||||
}
|
||||
@@ -563,10 +578,10 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
}
|
||||
GrVariable variable = clause.getDeclaredVariable();
|
||||
if (variable != null) {
|
||||
ReadWriteVariableInstruction writeInsn =
|
||||
new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, true);
|
||||
checkPending(writeInsn);
|
||||
addNode(writeInsn);
|
||||
ReadWriteVariableInstruction writeInst =
|
||||
new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, WRITE);
|
||||
checkPending(writeInst);
|
||||
addNode(writeInst);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,6 +770,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
|
||||
Set<Pair<InstructionImpl, GroovyPsiElement>> pendingAfterTry = new LinkedHashSet<Pair<InstructionImpl, GroovyPsiElement>>(myPending);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<InstructionImpl>[] throwers = new List[catchClauses.length];
|
||||
|
||||
for (int i = 0; i < catchClauses.length; i++) {
|
||||
@@ -772,7 +788,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
|
||||
final GrParameter parameter = catchClauses[i].getParameter();
|
||||
if (parameter != null) {
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, true));
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, WRITE));
|
||||
}
|
||||
catchClauses[i].accept(this);
|
||||
catches[i] = myHead;
|
||||
@@ -867,19 +883,73 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
public void visitMethod(GrMethod method) {
|
||||
}
|
||||
|
||||
public void visitTypeDefinition(GrTypeDefinition typeDefinition) {
|
||||
if (typeDefinition instanceof GrAnonymousClassDefinition) {
|
||||
super.visitTypeDefinition(typeDefinition);
|
||||
@Override
|
||||
public void visitClassInitializer(GrClassInitializer initializer) {
|
||||
}
|
||||
|
||||
public void visitTypeDefinition(final GrTypeDefinition typeDefinition) {
|
||||
if (!(typeDefinition instanceof GrAnonymousClassDefinition)) return;
|
||||
|
||||
final Set<String> vars = new HashSet<String>();
|
||||
typeDefinition.acceptChildren(new GroovyRecursiveElementVisitor() {
|
||||
private void collectVars(Instruction[] flow) {
|
||||
ReadWriteVariableInstruction[] reads = ControlFlowBuilderUtil.getReadsWithoutPriorWrites(flow);
|
||||
for (ReadWriteVariableInstruction instruction : reads) {
|
||||
vars.add(instruction.getVariableName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitField(GrField field) {
|
||||
GrExpression initializer = field.getInitializerGroovy();
|
||||
if (initializer != null) {
|
||||
Instruction[] flow = new ControlFlowBuilder(field.getProject()).buildControlFlow(initializer);
|
||||
collectVars(flow);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(GrMethod method) {
|
||||
GrOpenBlock block = method.getBlock();
|
||||
if (block != null) {
|
||||
collectVars(block.getControlFlow());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassInitializer(GrClassInitializer initializer) {
|
||||
GrOpenBlock block = initializer.getBlock();
|
||||
collectVars(block.getControlFlow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeDefinition(GrTypeDefinition typeDefinition) {
|
||||
typeDefinition.acceptChildren(this);
|
||||
}
|
||||
});
|
||||
|
||||
PsiField[] fields = typeDefinition.getAllFields();
|
||||
for (PsiField field : fields) {
|
||||
vars.remove(field.getName());
|
||||
}
|
||||
|
||||
for (String var : vars) {
|
||||
ReadWriteVariableInstruction i = new ReadWriteVariableInstruction(var, typeDefinition, myInstructionNumber++, READ);
|
||||
addNode(i);
|
||||
checkPending(i);
|
||||
}
|
||||
InstructionImpl i = new InstructionImpl(typeDefinition, myInstructionNumber++);
|
||||
addNode(i);
|
||||
checkPending(i);
|
||||
}
|
||||
|
||||
public void visitVariable(GrVariable variable) {
|
||||
super.visitVariable(variable);
|
||||
if (variable.getInitializerGroovy() != null ||
|
||||
variable.getParent() instanceof GrTupleDeclaration && ((GrTupleDeclaration)variable.getParent()).getInitializerGroovy() != null) {
|
||||
ReadWriteVariableInstruction writeInsn = new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, true);
|
||||
checkPending(writeInsn);
|
||||
addNode(writeInsn);
|
||||
ReadWriteVariableInstruction writeInst = new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, WRITE);
|
||||
checkPending(writeInst);
|
||||
addNode(writeInst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.formatter.GeeseUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrQualifiedReference;
|
||||
@@ -317,15 +316,13 @@ public class PsiImplUtil {
|
||||
private static int getExprPriorityLevel(GrExpression expr) {
|
||||
int priority = 0;
|
||||
//if (expr instanceof GrNewExpression) priority = 1;
|
||||
if (expr instanceof GrPostfixExpression) priority = 5;
|
||||
else if (expr instanceof GrUnaryExpression ||
|
||||
expr instanceof GrTypeCastExpression) priority = 6;
|
||||
if (expr instanceof GrUnaryExpression) priority = ((GrUnaryExpression)expr).isPostfix() ? 5 : 6;
|
||||
else if (expr instanceof GrTypeCastExpression) priority = 6;
|
||||
|
||||
else if (expr instanceof GrRangeExpressionImpl) priority = 11;
|
||||
|
||||
else if (expr instanceof GrBinaryExpression) {
|
||||
final IElementType opToken = ((GrBinaryExpression)expr).getOperationTokenType();
|
||||
LOG.assertTrue(opToken != null, expr.getText());
|
||||
|
||||
if (opToken == mSTAR_STAR) priority = 7;
|
||||
else if (opToken == mSTAR || opToken == mDIV) priority = 8;
|
||||
@@ -507,7 +504,7 @@ public class PsiImplUtil {
|
||||
} else {
|
||||
if (oldQualifier == null) {
|
||||
if (refNameElement != null) {
|
||||
node.addLeaf(GroovyTokenTypes.mDOT, ".", refNameElement.getNode());
|
||||
node.addLeaf(mDOT, ".", refNameElement.getNode());
|
||||
ref.addBefore(newQualifier, refNameElement.getPrevSibling());
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
|
||||
@@ -42,6 +43,11 @@ public class GrClassInitializerImpl extends GroovyPsiElementImpl implements GrCl
|
||||
super(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(GroovyElementVisitor visitor) {
|
||||
visitor.visitClassInitializer(this);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Class initializer";
|
||||
}
|
||||
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
*/
|
||||
public class GrPostfixExprImpl extends GrUnaryExpressionImpl implements GrPostfixExpression {
|
||||
|
||||
public GrPostfixExprImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Postfix expression";
|
||||
}
|
||||
|
||||
public void accept(GroovyElementVisitor visitor) {
|
||||
visitor.visitPostfixExpression(this);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user