Merge remote-tracking branch 'origin/master'

This commit is contained in:
Kirill Likhodedov
2012-03-20 17:08:41 +04:00
63 changed files with 811 additions and 304 deletions
@@ -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();
@@ -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() {
@@ -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"})
@@ -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) {
@@ -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");
@@ -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) {
@@ -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);
}
}
@@ -125,6 +125,11 @@ public class GrUnaryExpressionImpl extends GrExpressionImpl implements GrUnaryEx
return (GroovyResolveResult[])ResolveCache.getInstance(getProject()).resolveWithCaching(this, OUR_RESOLVER, false, incompleteCode);
}
@Override
public boolean isPostfix() {
return getFirstChild() instanceof GrExpression;
}
@Override
public PsiElement getElement() {
return this;
@@ -78,9 +78,9 @@ public class ResolveUtil {
}
/**
*
*
* @param place - place to start tree walk up
* @param processor
* @param processor
* @param processNonCodeMethods - this parameter tells us if we need non code members. But non code members are started to process only after we walk up any code block or script
* @return
*/
@@ -95,10 +95,6 @@ public class ResolveUtil {
while (run != null) {
if (!run.processDeclarations(processor, ResolveState.initial(), lastParent, place)) return false;
if (run instanceof GrClosableBlock) {
PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run);
if (superClass != null && !superClass.processDeclarations(processor, ResolveState.initial(), null, place)) return false;
}
if (processNonCodeMethods) {
if (!doProcessNonCodeMembers) {
if (run instanceof GrCodeBlock) doProcessNonCodeMembers = true;
@@ -115,6 +111,9 @@ public class ResolveUtil {
}
}
else if (run instanceof GrClosableBlock) {
PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run);
if (superClass != null && !superClass.processDeclarations(processor, ResolveState.initial(), null, place)) return false;
if (!GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor)) return false;
if (!GdkMethodUtil.withIteration((GrClosableBlock)run, processor, place)) return false;
}
@@ -669,7 +669,7 @@ public class ExpressionGenerator extends Generator {
@Override
public void visitUnaryExpression(GrUnaryExpression expression) {
final boolean postfix = expression instanceof GrPostfixExpression;
final boolean postfix = expression.isPostfix();
final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(expression.multiResolve(false));
final PsiElement resolved = resolveResult.getElement();
@@ -816,12 +816,12 @@ public class ExpressionGenerator extends Generator {
private static void writeSimpleUnary(GrExpression operand, GrUnaryExpression unary, ExpressionGenerator generator) {
String opTokenText = unary.getOperationToken().getText();
boolean isPrefix = !(unary instanceof GrPostfixExpression);
if (isPrefix) {
boolean isPostfix = unary.isPostfix();
if (!isPostfix) {
generator.getBuilder().append(opTokenText);
}
operand.accept(generator);
if (!isPrefix) {
if (isPostfix) {
generator.getBuilder().append(opTokenText);
}
}
@@ -37,6 +37,7 @@ import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilit
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyResultOfAssignmentUsedInspection
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyUncheckedAssignmentOfMemberOfRawTypeInspection
import org.jetbrains.plugins.groovy.codeInspection.confusing.ClashingGettersInspection
import org.jetbrains.plugins.groovy.codeInspection.confusing.GrUnusedIncDecInspection
import org.jetbrains.plugins.groovy.codeInspection.confusing.GroovyOctalIntegerInspection
import org.jetbrains.plugins.groovy.codeInspection.confusing.GroovyResultOfIncrementOrDecrementUsedInspection
import org.jetbrains.plugins.groovy.codeInspection.control.GroovyTrivialConditionalInspection
@@ -188,10 +189,10 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
public void testUnassigned3() throws Exception { doTest(new UnassignedVariableAccessInspection()); }
public void testUnassignedTryFinally() throws Exception { doTest(new UnassignedVariableAccessInspection()); }
public void testUnusedVariable() throws Exception { doTest(new UnusedDefInspection()); }
public void testDefinitionUsedInClosure() throws Exception { doTest(new UnusedDefInspection()); }
public void testDefinitionUsedInClosure2() throws Exception { doTest(new UnusedDefInspection()); }
public void testDefinitionUsedInSwitchCase() throws Exception { doTest(new UnusedDefInspection()); }
public void testUnusedVariable() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); }
public void testDefinitionUsedInClosure() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); }
public void testDefinitionUsedInClosure2() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); }
public void testDefinitionUsedInSwitchCase() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); }
public void testDuplicateInnerClass() throws Throwable{doTest();}
public void testThisInStaticContext() throws Throwable {doTest();}
@@ -248,8 +249,8 @@ class A {
public void testByteArrayArgument() throws Exception {doTest(new GroovyAssignabilityCheckInspection());}
public void testForLoopWithNestedEndlessLoop() throws Exception {doTest(new UnassignedVariableAccessInspection());}
public void testPrefixIncrementCfa() throws Exception {doTest(new UnusedDefInspection());}
public void testIfIncrementElseReturn() throws Exception {doTest(new UnusedDefInspection()); }
public void testPrefixIncrementCfa() throws Exception {doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection());}
public void testIfIncrementElseReturn() throws Exception {doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); }
public void testArrayLikeAccess() throws Exception {doTest();}
@@ -315,7 +316,7 @@ class A {
public void testBuiltInTypeInstantiation() {doTest();}
public void testSwitchControlFlow() {doTest(new UnusedDefInspection(), new GroovyResultOfAssignmentUsedInspection());}
public void testSwitchControlFlow() {doTest(new UnusedDefInspection(), new GroovyResultOfAssignmentUsedInspection(), new GrUnusedIncDecInspection());}
public void testRawTypeInAssignment() {doTest(new GroovyAssignabilityCheckInspection());}
@@ -325,7 +326,7 @@ class A {
IdeaTestUtil.assertTiming("", 10000, 1, new Runnable() {
@Override
public void run() {
doTest(new GroovyAssignabilityCheckInspection(), new UnusedDefInspection());
doTest(new GroovyAssignabilityCheckInspection(), new UnusedDefInspection(), new GrUnusedIncDecInspection());
}
});
}
@@ -397,7 +398,7 @@ class A {
doTest(new GroovyUnresolvedAccessInspection(), new GroovyUntypedAccessInspection());
}
public void testUsageInInjection() { doTest(new UnusedDefInspection()); }
public void testUsageInInjection() { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); }
public void testDuplicatedNamedArgs() {doTest();}
@@ -419,15 +420,19 @@ class A {
}
public void testUnusedDefsForArgs() {
doTest(new UnusedDefInspection());
doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection());
}
public void testUsedDefBeforeTry1() {
doTest(new UnusedDefInspection());
doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection());
}
public void testUsedDefBeforeTry2() {
doTest(new UnusedDefInspection());
doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection());
}
public void testUnusedInc() {
doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection())
}
public void testStringAssignableToChar() {
@@ -55,6 +55,8 @@ public class ControlFlowTest extends LightCodeInsightFixtureTestCase {
public void testIfInstanceofElse() throws Throwable { doTest(); }
public void testReturnMapFromClosure() {doTest();}
public void testSwitchInTryWithThrows() {doTest();}
public void testClosure() {doTest();}
public void testAnonymous() {doTest();}
public void doTest() {
final List<String> input = TestUtils.readInput(getTestDataPath() + getTestName(true) + ".test");
@@ -114,4 +114,7 @@ public class ExtractMethodTest extends LightGroovyTestCase {
public void testParamChangedInsideExtractedMethod() {doTest();}
public void testTerribleAppStatement() {doTest()}
public void testArgsUsedOnlyInClosure() {doTest()}
public void testArgsUsedOnlyInAnonymousClass() {doTest()}
}
@@ -0,0 +1,17 @@
int x = 0
[1, 2, 3].each (new Closure(this, this) {
void call() {
x++
}
})
print x
-----
0(1) element: null
1(2) WRITE x
2(3) READ x
3(4) element: Anonymous class
4(5) READ print
5(6) READ x
6(7) element: Call expression MAYBE_RETURN
7() element: null
+15
View File
@@ -0,0 +1,15 @@
int x = 0
[1, 2, 3].each {
x++
}
print x
-----
0(1) element: null
1(2) WRITE x
2(3) READ x
3(4) element: Closable block
4(5) READ print
5(6) READ x
6(7) element: Call expression MAYBE_RETURN
7() element: null
+3 -4
View File
@@ -3,8 +3,7 @@ for(int i = 0; i < 10; i++);
0(1) element: null
1(2) WRITE i
2(3) element: For statement
3(4,7) READ i
3(4,6) READ i
4(5) READ i
5(6) WRITE i
6(2) READ i
7() element: null
5(2) WRITE i
6() element: null
+3 -4
View File
@@ -8,9 +8,8 @@ while (true) {
1(2) WRITE i
2(3) element: WHILE statement
3(4,5) element: IF statement
4(9) READ i
4(8) READ i
5(6) element: IF statement
6(7) READ i
7(8) WRITE i
8(2) READ i
9() element: null
7(2) WRITE i
8() element: null
@@ -7,11 +7,10 @@ while (condition()) {
0(1) element: null
1(2) WRITE i
2(3) element: WHILE statement
3(4,10) READ condition
3(4,9) READ condition
4(5,6) element: IF statement
5(10) READ i
5(9) READ i
6(7) element: IF statement
7(8) READ i
8(9) WRITE i
9(2) READ i
10() element: null
8(2) WRITE i
9() element: null
@@ -0,0 +1,19 @@
def foo(b, c) {
<begin>[].each (new Closure(this, this) {
void call() {
b.plus(c)
}
})<end>
}
-----
def foo(b, c) {
testMethod(b, c)
}
private testMethod(b, c) {
[].each(new Closure(this, this) {
void call() {
b.plus(c)
}
})
}
@@ -0,0 +1,15 @@
def foo(b, c) {
<begin>[].each {
b.plus(c)
}<end>
}
-----
def foo(b, c) {
testMethod(b, c)
}
private testMethod(b, c) {
[].each {
b.plus(c)
}
}
@@ -12,7 +12,7 @@ class S {
-----
class S {
def r() {
Closure sin = <caret>testMethod()
Closure<Double> sin = <caret>testMethod()
10.times {
@@ -21,7 +21,7 @@ class S {
}
private Closure testMethod() {
private Closure<Double> testMethod() {
Closure sin = {x -> Math.sin(x)}
return sin
}
@@ -1,7 +1,7 @@
int idx
<warning descr="Assignment is not used">idx</warning> = 2
idx = 3
if (++idx == 8) { //Assignment is used here
if (++idx == 8) {
idx = 33
}
print idx
+7
View File
@@ -0,0 +1,7 @@
def a = 4
print (++a)
print (a<warning descr="Unused ++">++</warning>)
def b = 3
b<warning descr="Unused ++">++</warning>
<warning descr="Assignment is not used">b</warning> = 3
@@ -3,8 +3,8 @@
Groovy script
Unary expression
PsiElement(!)('!')
Postfix expression
Postfix expression
Unary expression
Unary expression
Literal
PsiElement(Integer)('3')
PsiElement(++)('++')
@@ -31,7 +31,7 @@ Groovy script
PsiWhiteSpace(' ')
PsiElement(;)(';')
PsiWhiteSpace(' ')
Postfix expression
Unary expression
Reference expression
PsiElement(identifier)('i')
PsiElement(++)('++')
@@ -26,7 +26,7 @@ Groovy script
PsiElement(Integer)('5')
PsiElement(;)(';')
PsiWhiteSpace(' ')
Postfix expression
Unary expression
Reference expression
PsiElement(identifier)('i')
PsiElement(++)('++')
@@ -31,7 +31,7 @@ Groovy script
PsiWhiteSpace(' ')
PsiElement(;)(';')
PsiWhiteSpace(' ')
Postfix expression
Unary expression
Reference expression
PsiElement(identifier)('i')
PsiElement(++)('++')
@@ -17,7 +17,9 @@ package org.jetbrains.idea.maven.dom;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.GenericDomValue;
@@ -34,13 +36,15 @@ import org.jetbrains.idea.maven.dom.converters.MavenPluginCustomParameterValueCo
import org.jetbrains.idea.maven.dom.model.MavenDomConfiguration;
import org.jetbrains.idea.maven.dom.model.MavenDomConfigurationParameter;
import org.jetbrains.idea.maven.dom.model.MavenDomPluginExecution;
import org.jetbrains.idea.maven.dom.model.MavenDomPluginManagement;
import org.jetbrains.idea.maven.dom.plugin.MavenDomMojo;
import org.jetbrains.idea.maven.dom.plugin.MavenDomParameter;
import org.jetbrains.idea.maven.dom.plugin.MavenDomPluginModel;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class MavenPluginConfigurationDomExtender extends DomExtender<MavenDomConfiguration> {
public static final Key<ParameterData> PLUGIN_PARAMETER_KEY = Key.create("MavenPluginConfigurationDomExtender.PLUGIN_PARAMETER_KEY");
@@ -53,21 +57,26 @@ public class MavenPluginConfigurationDomExtender extends DomExtender<MavenDomCon
return;
}
boolean isInPluginManagement = false;// isInPluginManagement(config);
boolean isInPluginManagement = isInPluginManagement(config);
for (ParameterData each : collectParameters(pluginModel, config)) {
registerPluginParameter(isInPluginManagement, r, each);
}
}
private static boolean isInPluginManagement(MavenDomConfiguration config) {
DomElement pluginNode = config.getParent();
if (pluginNode == null) return false;
private static boolean isInPluginManagement(MavenDomConfiguration pluginNode) {
XmlElement xmlElement = pluginNode.getXmlElement();
if (xmlElement == null) return false;
DomElement pluginsNode = pluginNode.getParent();
if (pluginsNode == null) return false;
PsiElement pluginTag = xmlElement.getParent();
if (pluginTag == null) return false;
return pluginsNode.getParent() instanceof MavenDomPluginManagement;
PsiElement pluginsTag = pluginTag.getParent();
if (pluginsTag == null) return false;
PsiElement pluginManagementTag = pluginsTag.getParent();
return pluginManagementTag instanceof XmlTag && "pluginManagement".equals(((XmlTag)pluginManagementTag).getName());
}
private static Collection<ParameterData> collectParameters(MavenDomPluginModel pluginModel, MavenDomConfiguration config) {
@@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.xml.DomElement;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.model.MavenDomPlugin;
import org.jetbrains.idea.maven.dom.plugin.MavenDomPluginModel;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
@@ -28,6 +29,7 @@ import org.jetbrains.idea.maven.utils.MavenArtifactUtil;
import java.io.File;
public class MavenPluginDomUtil {
@Nullable
public static MavenDomPluginModel getMavenPluginModel(DomElement element) {
Project p = element.getXmlElement().getProject();
@@ -40,6 +42,7 @@ public class MavenPluginDomUtil {
return MavenDomUtil.getMavenDomModel(p, pluginXmlFile, MavenDomPluginModel.class);
}
@Nullable
private static VirtualFile getPluginXmlFile(Project p, MavenDomPlugin pluginElement) {
String groupId = pluginElement.getGroupId().getStringValue();
String artifactId = pluginElement.getArtifactId().getStringValue();