Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexander Lobas
2012-03-20 21:48:20 +04:00
132 changed files with 1344 additions and 615 deletions
@@ -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);
}
}
@@ -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);
@@ -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));
}
}
}
}
@@ -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();
@@ -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);
}
}
@@ -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() {
@@ -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
@@ -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()) {
@@ -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;
}
@@ -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;
@@ -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
);
@@ -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);
}
}
}
@@ -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
+1 -1
View File
@@ -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;
}
});
}
@@ -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);
}
}
@@ -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");
@@ -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
@@ -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>
+3
View File
@@ -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"/>
@@ -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;
}
@@ -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}
@@ -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);
}
});
}
@@ -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;
}
}
@@ -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);
@@ -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;
@@ -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) {
@@ -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;
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
@@ -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 {
@@ -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);
}
}
@@ -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 {
}
@@ -35,4 +35,6 @@ public interface GrUnaryExpression extends GrExpression, PsiPolyVariantReference
@NotNull
@Override
GroovyResolveResult[] multiResolve(final boolean incompleteCode);
boolean isPostfix();
}
@@ -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() {
@@ -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());
}
}
@@ -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";
}
@@ -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