Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2017-02-13 20:18:24 +03:00
266 changed files with 2718 additions and 1571 deletions
+5 -2
View File
@@ -34,10 +34,13 @@
implementationClass="org.intellij.lang.regexp.inspection.SingleCharAlternationInspection"/>
<localInspection groupName="RegExp" language="RegExp" shortName="OctalEscape" displayName="Octal escape" enabledByDefault="false"
level="WARNING" implementationClass="org.intellij.lang.regexp.inspection.OctalEscapeInspection"/>
<localInspection groupName="RegExp" language="RegExp" shortName="ReDoS" displayName="Exponential backtracking" enabledByDefault="true"
level="WARNING" implementationClass="org.intellij.lang.regexp.inspection.ReDoSInspection"/>
<!--<localInspection groupName="RegExp" language="RegExp" shortName="ReDoS" displayName="Exponential backtracking" enabledByDefault="true"
level="WARNING" implementationClass="org.intellij.lang.regexp.inspection.ReDoSInspection"/>-->
<localInspection groupName="RegExp" language="RegExp" shortName="DuplicateAlternationBranch"
displayName="Duplicate branch in alternation" enabledByDefault="true" level="WARNING"
implementationClass="org.intellij.lang.regexp.inspection.DuplicateAlternationBranchInspection"/>
<localInspection groupName="RegExp" language="RegExp" shortName="EscapedMetaCharacter" displayName="Escaped meta character"
enabledByDefault="false" level="WARNING"
implementationClass="org.intellij.lang.regexp.inspection.EscapedMetaCharacterInspection"/>
</extensions>
</idea-plugin>
@@ -0,0 +1,12 @@
<html>
<body>
Reports the escaped meta characters, e.g. <b><code>\.</code></b>.
Some RegExp coding styles specify that meta characters should be placed inside a character class,
to make the regular expression easier to understand.
For example the regex <b><code>\d+\.\d+</code></b> would be written as <code>\d+[.]\d+</code>.
This inspection does not warn about the meta character <b><code>[</code></b>, <b><code>]</code></b> and <b><code>^</code></b>,
because those would need additional escaping inside a character class.
<!-- tooltip end -->
<p><small>New in 2017.1</small>
</body>
</html>
@@ -0,0 +1,115 @@
/*
* Copyright 2000-2017 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.intellij.lang.regexp.inspection;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import org.intellij.lang.regexp.RegExpTT;
import org.intellij.lang.regexp.psi.RegExpBranch;
import org.intellij.lang.regexp.psi.RegExpChar;
import org.intellij.lang.regexp.psi.RegExpElementVisitor;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
/**
* @author Bas Leijdekkers
*/
public class EscapedMetaCharacterInspection extends LocalInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new EscapedMetaCharacterVisitor(holder);
}
private static class EscapedMetaCharacterVisitor extends RegExpElementVisitor {
private final ProblemsHolder myHolder;
public EscapedMetaCharacterVisitor(ProblemsHolder holder) {
myHolder = holder;
}
@Override
public void visitRegExpChar(RegExpChar ch) {
if (ch.getType() != RegExpChar.Type.CHAR) {
return;
}
final String text = ch.getUnescapedText();
if (text.length() != 2 || text.charAt(0) != '\\') {
return;
}
final char c = text.charAt(1);
switch (c) {
case '{':
case '}':
case '(':
case ')':
case '.':
case '*':
case '+':
case '?':
case '|':
case '$':
final ASTNode node = ch.getNode().getFirstChildNode();
if (node != null && node.getElementType() == RegExpTT.REDUNDANT_ESCAPE) {
return;
}
myHolder.registerProblem(ch, "Escaped meta character <code>" + c + "</code>", new EscapedMetaCharacterFix(c));
break;
}
}
}
private static class EscapedMetaCharacterFix implements LocalQuickFix {
private final char myC;
EscapedMetaCharacterFix(char c) {
myC = c;
}
@Nls
@NotNull
@Override
public String getName() {
return "Replace with '[" + myC + "]'";
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return "Replace with character inside class";
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (!(element instanceof RegExpChar)) {
return;
}
final RegExpBranch branch = RegExpFactory.createBranchFromText("[" + myC + ']', element);
element.replace(branch.getFirstChild());
}
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2000-2017 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.intellij.lang.regexp.inspection;
import com.intellij.codeInspection.LocalInspectionTool;
import org.jetbrains.annotations.NotNull;
/**
* @author Bas Leijdekkers
*/
public class EscapedMetaCharacterInspectionTest extends RegExpInspectionTestCase {
public void testSimple() {
quickfixTest("<warning descr=\"Escaped meta character '.'\">\\.</warning>", "[.]", "Replace with '[.]'");
}
public void testNoWarn() {
highlightTest("\\[\\^\\]");
}
public void testHighlighting() {
highlightTest("<warning descr=\"Escaped meta character '{'\">\\{</warning>" +
"\\}" + // already has redundant character escape warning
"<warning descr=\"Escaped meta character '('\">\\(</warning>" +
"<warning descr=\"Escaped meta character ')'\">\\)</warning>" +
"<warning descr=\"Escaped meta character '.'\">\\.</warning>" +
"<warning descr=\"Escaped meta character '*'\">\\*</warning>" +
"<warning descr=\"Escaped meta character '+'\">\\+</warning>" +
"<warning descr=\"Escaped meta character '?'\">\\?</warning>" +
"<warning descr=\"Escaped meta character '|'\">\\|</warning>" +
"<warning descr=\"Escaped meta character '$'\">\\$</warning>");
}
@NotNull
@Override
protected LocalInspectionTool getInspection() {
return new EscapedMetaCharacterInspection();
}
}
@@ -34,14 +34,14 @@ import com.sun.jdi.VMDisconnectedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
/**
* @author lex
*/
public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerCommandImpl> implements DebuggerManagerThread, Disposable {
private static final Logger LOG = Logger.getInstance(DebuggerManagerThreadImpl.class);
public static final int COMMAND_TIMEOUT = 3000;
static final int COMMAND_TIMEOUT = 3000;
private volatile boolean myDisposed;
@@ -55,6 +55,19 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerComma
myDisposed = true;
}
private static void waitForTerminateFutureToComplete(@NotNull Future<?> future) {
try {
LOG.debug("Waiting for " + future);
future.get(1, TimeUnit.MINUTES);
}
catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
catch (TimeoutException e) {
throw new RuntimeException("Termination request is still pending", e);
}
}
@TestOnly
public static DebuggerManagerThreadImpl createTestInstance(@NotNull Disposable parent, Project project) {
return new DebuggerManagerThreadImpl(parent, project);
@@ -106,13 +119,13 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerComma
* if worker thread is still processing the same command
* calls terminateCommand
*/
public void terminateAndInvoke(DebuggerCommandImpl command, int terminateTimeout) {
public void terminateAndInvoke(DebuggerCommandImpl command, int terminateTimeoutMillis) {
final DebuggerCommandImpl currentCommand = myEvents.getCurrentEvent();
invoke(command);
if (currentCommand != null) {
AppExecutorUtil.getAppScheduledExecutorService().schedule(
final ScheduledFuture<?> future = AppExecutorUtil.getAppScheduledExecutorService().schedule(
() -> {
if (currentCommand == myEvents.getCurrentEvent()) {
// if current command is still in progress, cancel it
@@ -131,7 +144,10 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerComma
}
}
}
}, terminateTimeout, TimeUnit.MILLISECONDS);
}, terminateTimeoutMillis, TimeUnit.MILLISECONDS);
// register on project instead of this because it would cause significant delays on each session termination otherwise
Disposer.register(myProject, () -> waitForTerminateFutureToComplete(future));
}
}
@@ -174,7 +190,7 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerComma
}
public void startLongProcessAndFork(Runnable process) {
void startLongProcessAndFork(Runnable process) {
assertIsManagerThread();
startNewWorkerThread();
@@ -235,7 +251,7 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerComma
}
public void restartIfNeeded () {
void restartIfNeeded() {
if (myEvents.isClosed()) {
myEvents.reopen();
startNewWorkerThread();
@@ -20,18 +20,18 @@ import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.Project;
import com.intellij.debugger.memory.component.InstancesTracker;
public class EnableBackgroundTrackingAction extends ToggleAction{
public class EnableBackgroundTrackingAction extends ToggleAction {
@Override
public boolean isSelected(AnActionEvent e) {
Project project = e.getProject();
return project != null && InstancesTracker.getInstance(project).isBackgroundTrackingEnabled();
return project != null && !project.isDisposed() && InstancesTracker.getInstance(project).isBackgroundTrackingEnabled();
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
Project project = e.getProject();
if (project != null) {
if (project != null && !project.isDisposed()) {
InstancesTracker.getInstance(project).setBackgroundTackingEnabled(state);
}
}
@@ -42,7 +42,7 @@ public class TrackInstancesToggleAction extends ToggleAction {
public boolean isSelected(AnActionEvent e) {
ReferenceType selectedClass = getSelectedClass(e);
final Project project = e.getProject();
if (project != null && selectedClass != null) {
if (project != null && selectedClass != null && !project.isDisposed()) {
InstancesTracker tracker = InstancesTracker.getInstance(project);
return tracker.isTracked(selectedClass.name());
}
@@ -54,7 +54,7 @@ public class TrackInstancesToggleAction extends ToggleAction {
public void setSelected(AnActionEvent e, boolean state) {
final ReferenceType selectedClass = getSelectedClass(e);
final Project project = e.getProject();
if (selectedClass != null && project != null) {
if (selectedClass != null && project != null && !project.isDisposed()) {
InstancesTracker tracker = InstancesTracker.getInstance(project);
boolean isAlreadyTracked = tracker.isTracked(selectedClass.name());
@@ -31,9 +31,9 @@ import java.util.concurrent.ConcurrentHashMap;
@State(name = "InstancesTracker", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
public class InstancesTracker extends AbstractProjectComponent
implements PersistentStateComponent<InstancesTracker.MyState> {
implements PersistentStateComponent<InstancesTracker.MyState> {
private final EventDispatcher<InstancesTrackerListener> myDispatcher =
EventDispatcher.create(InstancesTrackerListener.class);
EventDispatcher.create(InstancesTrackerListener.class);
private MyState myState = new MyState();
public InstancesTracker(Project project) {
@@ -84,7 +84,7 @@ public class InstancesTracker extends AbstractProjectComponent
public void setBackgroundTackingEnabled(boolean state) {
boolean oldState = myState.isBackgroundTrackingEnabled;
if(state != oldState) {
if (state != oldState) {
myState.isBackgroundTrackingEnabled = state;
myDispatcher.getMulticaster().backgroundTrackingValueChanged(state);
}
@@ -104,7 +104,6 @@ public class InstancesTracker extends AbstractProjectComponent
static class MyState {
boolean isBackgroundTrackingEnabled = false;
@NotNull
@AbstractCollection(surroundWithTag = false, elementTypes = {Map.Entry.class})
final Map<String, TrackingType> classes = new ConcurrentHashMap<>();
@@ -51,13 +51,19 @@ public class MemoryViewComponent extends AbstractProjectComponent {
@Override
public void processStarted(@NotNull XDebugProcess debugProcess) {
final XDebugSession session = debugProcess.getSession();
final Project project = session.getProject();
final DebugProcess javaProcess =
DebuggerManager.getInstance(session.getProject()).getDebugProcess(debugProcess.getProcessHandler());
DebuggerManager.getInstance(project).getDebugProcess(debugProcess.getProcessHandler());
if (javaProcess instanceof DebugProcessImpl) {
final DebugProcessImpl processImpl = (DebugProcessImpl)javaProcess;
ApplicationManager.getApplication().invokeLater(() -> {
if (project.isDisposed()) {
return;
}
final InstancesTracker tracker = InstancesTracker.getInstance(project);
final RunnerLayoutUi ui = session.getUI();
final ClassesFilteredView classesFilteredView = new ClassesFilteredView(session, processImpl);
final ClassesFilteredView classesFilteredView = new ClassesFilteredView(session, processImpl, tracker);
classesFilteredView.setActive(true);
final Content memoryViewContent =
ui.createContent(MEMORY_VIEW_CONTENT_ID, classesFilteredView, "Memory View",
@@ -69,16 +69,16 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
private volatile boolean myIsBackgroundTrackingEnabled;
public ConstructorInstancesTracker(@NotNull ReferenceType ref,
@NotNull XDebugSession debugSession) {
@NotNull XDebugSession debugSession,
@NotNull InstancesTracker instancesTracker) {
myReference = ref;
myProject = debugSession.getProject();
myIsBackgroundTrackingEnabled = InstancesTracker.getInstance(myProject)
.isBackgroundTrackingEnabled();
myIsBackgroundTrackingEnabled = instancesTracker.isBackgroundTrackingEnabled();
final DebugProcessImpl debugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject)
.getDebugProcess(debugSession.getDebugProcess().getProcessHandler());
InstancesTracker.getInstance(myProject).addTrackerListener(new InstancesTrackerListener() {
instancesTracker.addTrackerListener(new InstancesTrackerListener() {
@Override
public void backgroundTrackingValueChanged(boolean newState) {
if (myIsBackgroundTrackingEnabled != newState) {
@@ -62,6 +62,7 @@ import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -104,12 +105,14 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
*/
private boolean myIsActive;
public ClassesFilteredView(@NotNull XDebugSession debugSession, @NotNull DebugProcessImpl debugProcess) {
public ClassesFilteredView(@NotNull XDebugSession debugSession,
@NotNull DebugProcessImpl debugProcess,
@NotNull InstancesTracker tracker) {
super();
myProject = debugSession.getProject();
myInstancesTracker = InstancesTracker.getInstance(myProject);
myInstancesTracker = tracker;
final InstancesTrackerListener instancesTrackerListener = new InstancesTrackerListener() {
@Override
public void classChanged(@NotNull String name, @NotNull TrackingType type) {
@@ -147,7 +150,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
@Override
protected void action() throws Exception {
final boolean activated = myIsTrackersActivated.get();
myInstancesTracker.getTrackedClasses().forEach((className, type) -> {
tracker.getTrackedClasses().forEach((className, type) -> {
List<ReferenceType> classes = debugProcess.getVirtualMachineProxy().classesByName(className);
if (classes.isEmpty()) {
new ClassPreparedListener(className, debugSession) {
@@ -164,14 +167,14 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
}
});
myInstancesTracker.addTrackerListener(instancesTrackerListener, ClassesFilteredView.this);
tracker.addTrackerListener(instancesTrackerListener, ClassesFilteredView.this);
}
});
final MemoryViewManagerState memoryViewManagerState = MemoryViewManager.getInstance().getState();
myTable = new ClassesTable(debugSession, memoryViewManagerState.isShowWithDiffOnly,
memoryViewManagerState.isShowWithInstancesOnly, memoryViewManagerState.isShowTrackedOnly, this);
myTable = new ClassesTable(tracker, this, memoryViewManagerState.isShowWithDiffOnly,
memoryViewManagerState.isShowWithInstancesOnly, memoryViewManagerState.isShowTrackedOnly);
myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_RUNNING);
Disposer.register(this, myTable);
@@ -286,7 +289,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
return;
}
final ConstructorInstancesTracker tracker = new ConstructorInstancesTracker(ref, debugSession);
final ConstructorInstancesTracker tracker = new ConstructorInstancesTracker(ref, debugSession, myInstancesTracker);
tracker.setBackgroundMode(!myIsActive);
if (isTrackerEnabled) {
tracker.enable();
@@ -303,7 +306,10 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
private void handleClassSelection(@Nullable ReferenceType ref) {
final XDebugSession debugSession = XDebuggerManager.getInstance(myProject).getCurrentSession();
if (ref != null && debugSession != null && debugSession.isSuspended()) {
new InstancesWindow(debugSession, limit -> ref.instances(limit), ref.name()).show();
new InstancesWindow(debugSession, limit -> {
final List<ObjectReference> instances = ref.instances(limit);
return instances == null ? Collections.emptyList() : instances;
}, ref.name()).show();
}
}
@@ -37,7 +37,6 @@ import com.intellij.ui.table.JBTable;
import com.intellij.util.containers.FList;
import com.intellij.util.ui.JBDimension;
import com.intellij.util.ui.JBUI;
import com.intellij.xdebugger.XDebugSession;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ReferenceType;
import org.jetbrains.annotations.NonNls;
@@ -79,14 +78,15 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable {
private volatile List<ReferenceType> myItems = Collections.unmodifiableList(new ArrayList<>());
ClassesTable(@NotNull XDebugSession session, boolean onlyWithDiff, boolean onlyWithInstances,
boolean onlyTracked, @NotNull ClassesFilteredView parent) {
public ClassesTable(@NotNull InstancesTracker tracker, @NotNull ClassesFilteredView parent, boolean onlyWithDiff,
boolean onlyWithInstances,
boolean onlyTracked) {
setModel(myModel);
myOnlyWithDiff = onlyWithDiff;
myOnlyWithInstances = onlyWithInstances;
myOnlyTracked = onlyTracked;
myInstancesTracker = InstancesTracker.getInstance(session.getProject());
myInstancesTracker = tracker;
myParent = parent;
TableColumn classesColumn = getColumnModel().getColumn(DiffViewTableModel.CLASSNAME_COLUMN_INDEX);
@@ -24,6 +24,7 @@ import com.intellij.debugger.memory.utils.StackFrameItem;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.ui.JBSplitter;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane;
@@ -49,9 +50,10 @@ class InstancesWithStackFrameView {
private boolean myIsHided = false;
InstancesWithStackFrameView(@NotNull XDebugSession debugSession, @NotNull InstancesTree tree,
@NotNull StackFrameList list, String className) {
@NotNull StackFrameList list, @NotNull String className) {
mySplitter.setFirstComponent(new JBScrollPane(tree));
final Project project = debugSession.getProject();
list.setEmptyText(EMPTY_TEXT_WHEN_ITEM_NOT_SELECTED);
JLabel stackTraceLabel;
if (isArrayType(className)) {
@@ -63,8 +65,10 @@ class InstancesWithStackFrameView {
new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
InstancesTracker.getInstance(debugSession.getProject())
.add(className, TrackingType.CREATION);
final Project project = e.getProject();
if (project != null && !project.isDisposed()) {
InstancesTracker.getInstance(project).add(className, TrackingType.CREATION);
}
}
});
@@ -77,30 +81,32 @@ class InstancesWithStackFrameView {
JComponent stackComponent = new JBScrollPane(list);
InstancesTracker instancesTracker = InstancesTracker.getInstance(debugSession.getProject());
instancesTracker.addTrackerListener(new InstancesTrackerListener() {
@Override
public void classChanged(@NotNull String name, @NotNull TrackingType type) {
if (Objects.equals(className, name) && type == TrackingType.CREATION) {
mySplitter.setSecondComponent(stackComponent);
if (!project.isDisposed()) {
final InstancesTracker tracker = InstancesTracker.getInstance(project);
tracker.addTrackerListener(new InstancesTrackerListener() {
@Override
public void classChanged(@NotNull String name, @NotNull TrackingType type) {
if (Objects.equals(className, name) && type == TrackingType.CREATION) {
mySplitter.setSecondComponent(stackComponent);
}
}
}
@Override
public void classRemoved(@NotNull String name) {
if (Objects.equals(name, className)) {
mySplitter.setSecondComponent(stackTraceLabel);
@Override
public void classRemoved(@NotNull String name) {
if (Objects.equals(name, className)) {
mySplitter.setSecondComponent(stackTraceLabel);
}
}
}
}, tree);
}, tree);
mySplitter.setSecondComponent(instancesTracker.isTracked(className) ? stackComponent : stackTraceLabel);
mySplitter.setSecondComponent(tracker.isTracked(className) ? stackComponent : stackTraceLabel);
}
mySplitter.setHonorComponentsMinimumSize(false);
myHidedProportion = DEFAULT_SPLITTER_PROPORTION;
final MemoryViewDebugProcessData data =
DebuggerManager.getInstance(debugSession.getProject()).getDebugProcess(debugSession.getDebugProcess().getProcessHandler())
DebuggerManager.getInstance(project).getDebugProcess(debugSession.getDebugProcess().getProcessHandler())
.getUserData(MemoryViewDebugProcessData.KEY);
tree.addTreeSelectionListener(e -> {
ObjectReference ref = tree.getSelectedReference();
@@ -17,6 +17,7 @@ package com.intellij.debugger.settings;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserFactory;
@@ -31,8 +32,11 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWrapper;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.util.PlatformIcons;
import com.intellij.util.ui.ItemRemovable;
import com.intellij.util.xmlb.XmlSerializer;
import one.util.streamex.IntStreamEx;
import one.util.streamex.StreamEx;
import org.jdom.Document;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
@@ -48,6 +52,8 @@ import java.util.List;
* @author egor
*/
public class CaptureConfigurable implements SearchableConfigurable {
private static final Logger LOG = Logger.getInstance(CaptureConfigurable.class);
private MyTableModel myTableModel;
@NotNull
@@ -93,6 +99,26 @@ public class CaptureConfigurable implements SearchableConfigurable {
}
});
decorator.addExtraAction(new DumbAwareActionButton("Duplicate", "Duplicate", PlatformIcons.COPY_ICON) {
@Override
public boolean isEnabled() {
return table.getSelectedRowCount() == 1;
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
selectedCapturePoints(table).forEach(c -> {
try {
myTableModel.add(c.clone());
table.getSelectionModel().setSelectionInterval(table.getRowCount() - 1, table.getRowCount() - 1);
}
catch (CloneNotSupportedException ex) {
LOG.error(ex);
}
});
}
});
decorator.addExtraAction(new DumbAwareActionButton("Import", "Import", AllIcons.Actions.Install) {
@Override
public void actionPerformed(@NotNull final AnActionEvent e) {
@@ -136,16 +162,16 @@ public class CaptureConfigurable implements SearchableConfigurable {
if (wrapper == null) return;
Element rootElement = new Element("capture-points");
for (int row : table.getSelectedRows()) {
CapturePoint c = myTableModel.get(table.convertRowIndexToModel(row));
selectedCapturePoints(table).forEach(c -> {
try {
CapturePoint clone = c.clone();
clone.myEnabled = false;
rootElement.addContent(XmlSerializer.serialize(clone));
}
catch (CloneNotSupportedException ignore) {
catch (CloneNotSupportedException ex) {
LOG.error(ex);
}
}
});
try {
JDOMUtil.writeDocument(new Document(rootElement), wrapper.getFile(), "\n");
}
@@ -164,6 +190,10 @@ public class CaptureConfigurable implements SearchableConfigurable {
return decorator.createPanel();
}
private StreamEx<CapturePoint> selectedCapturePoints(JBTable table) {
return IntStreamEx.of(table.getSelectedRows()).map(table::convertRowIndexToModel).mapToObj(myTableModel::get);
}
private static class MyTableModel extends AbstractTableModel implements ItemRemovable {
public static final int ENABLED_COLUMN = 0;
public static final int CLASS_COLUMN = 1;
@@ -298,7 +298,7 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
if (mainClass != null) {
PsiJavaModule mainModule = JavaModuleGraphUtil.findDescriptorByElement(mainClass);
if (mainModule != null) {
params.setModuleName(mainModule.getModuleName());
params.setModuleName(mainModule.getName());
PathsList classPath = params.getClassPath(), modulePath = params.getModulePath();
modulePath.addAll(classPath.getPathList());
classPath.clear();
@@ -128,7 +128,7 @@ public class JavaModuleInsight extends ModuleInsight {
if (javaModule == null) {
throw new IncorrectOperationException("Incorrect module declaration '" + file.getPath() + "'");
}
ModuleInfo info = new ModuleInfo(javaModule.getModuleName());
ModuleInfo info = new ModuleInfo(javaModule.getName());
javaModule.accept(new ModuleInfoVisitor(info));
return info;
});
@@ -429,11 +429,12 @@ public class HighlightMethodUtil {
else {
PsiReferenceExpression methodExpression = methodCall.getMethodExpression();
PsiReferenceParameterList typeArgumentList = methodCall.getTypeArgumentList();
PsiSubstitutor applicabilitySubstitutor = candidateInfo.getSubstitutor(false);
if (typeArgumentList.getTypeArguments().length == 0 && resolvedMethod.hasTypeParameters()) {
highlightInfo = GenericsHighlightUtil.checkInferredTypeArguments(resolvedMethod, methodCall, substitutor);
highlightInfo = GenericsHighlightUtil.checkInferredTypeArguments(resolvedMethod, methodCall, applicabilitySubstitutor);
}
else {
highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, methodExpression, substitutor, javaSdkVersion);
highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, methodExpression, applicabilitySubstitutor, javaSdkVersion);
}
}
}
@@ -66,7 +66,7 @@ public class JavaModuleGraphUtil {
Map<String, Set<String>> exports = CachedValuesManager.getCachedValue(source, () ->
Result.create(exportsMap(source), source.getContainingFile()));
Set<String> targets = exports.get(packageName);
return targets != null && (targets.isEmpty() || targets.contains(target.getModuleName()));
return targets != null && (targets.isEmpty() || targets.contains(target.getName()));
}
public static boolean reads(@NotNull PsiJavaModule source, @NotNull PsiJavaModule destination) {
@@ -178,7 +178,7 @@ public class JavaModuleGraphUtil {
}
public static String key(PsiJavaModule module, PsiJavaModule exporter) {
return module.getModuleName() + '/' + exporter.getModuleName();
return module.getName() + '/' + exporter.getName();
}
}
@@ -223,13 +223,13 @@ public class ModuleHighlightUtil {
return moduleResolveError(refElement, ref);
}
else if (target == container) {
String message = JavaErrorMessages.message("module.cyclic.dependence", container.getModuleName());
String message = JavaErrorMessages.message("module.cyclic.dependence", container.getName());
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refElement).description(message).create();
}
else {
Collection<PsiJavaModule> cycle = JavaModuleGraphUtil.findCycle((PsiJavaModule)target);
if (cycle != null && cycle.contains(container)) {
Stream<String> stream = cycle.stream().map(PsiJavaModule::getModuleName);
Stream<String> stream = cycle.stream().map(PsiJavaModule::getName);
if (ApplicationManager.getApplication().isUnitTestMode()) stream = stream.sorted();
String message = JavaErrorMessages.message("module.cyclic.dependence", stream.collect(Collectors.joining(", ")));
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refElement).description(message).create();
@@ -373,8 +373,8 @@ public class ModuleHighlightUtil {
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(ref).description(message).create();
}
String refModuleName = refModule.getModuleName();
String requiredName = targetModule.getModuleName();
String refModuleName = refModule.getName();
String requiredName = targetModule.getName();
if (!(targetModule instanceof LightJavaModule || JavaModuleGraphUtil.exports(targetModule, packageName, refModule))) {
String message = JavaErrorMessages.message("module.package.not.exported", requiredName, packageName, refModuleName);
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(ref).description(message).create();
@@ -421,7 +421,7 @@ public class ModuleHighlightUtil {
private static TextRange range(PsiJavaModule module) {
PsiKeyword kw = PsiTreeUtil.getChildOfType(module, PsiKeyword.class);
return new TextRange(kw != null ? kw.getTextOffset() : module.getTextOffset(), module.getNameElement().getTextRange().getEndOffset());
return new TextRange(kw != null ? kw.getTextOffset() : module.getTextOffset(), module.getNameIdentifier().getTextRange().getEndOffset());
}
private static PsiElement range(PsiJavaCodeReferenceElement refElement) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -66,8 +66,7 @@ public class AddRequiredModuleFix implements IntentionAction {
if (module == null) return;
PsiJavaParserFacade parserFacade = JavaPsiFacade.getInstance(project).getParserFacade();
PsiJavaModule tempModule =
parserFacade.createModuleFromText("module " + module.getModuleName() + " { requires " + myRequiredName + "; }");
PsiJavaModule tempModule = parserFacade.createModuleFromText("module " + module.getName() + " { requires " + myRequiredName + "; }");
Iterable<PsiRequiresStatement> tempModuleRequires = tempModule.getRequires();
PsiRequiresStatement requiresStatement = tempModuleRequires.iterator().next();
@@ -90,7 +89,7 @@ public class AddRequiredModuleFix implements IntentionAction {
@Nullable
private static PsiElement getLBrace(@NotNull PsiJavaModule module) {
PsiJavaModuleReferenceElement nameElement = module.getNameElement();
PsiJavaModuleReferenceElement nameElement = module.getNameIdentifier();
for (PsiElement element = nameElement.getNextSibling(); element != null; element = element.getNextSibling()) {
if (PsiUtil.isJavaToken(element, JavaTokenType.LBRACE)) {
return element;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -26,6 +26,7 @@ package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.PsiEquivalenceUtil;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.impl.quickfix.SimplifyBooleanExpressionFix;
import com.intellij.codeInsight.intention.impl.AddNotNullAnnotationFix;
@@ -48,12 +49,10 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.extractMethod.ExtractMethodUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.siyeh.ig.psiutils.TypeUtils;
import one.util.streamex.StreamEx;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -73,6 +72,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
public boolean REPORT_CONSTANT_REFERENCE_VALUES = true;
public boolean REPORT_NULLS_PASSED_TO_NOT_NULL_PARAMETER = true;
public boolean REPORT_NULLABLE_METHODS_RETURNING_NOT_NULL = true;
public boolean REPORT_UNCHECKED_OPTIONALS = true;
@Override
public JComponent createOptionsPanel() {
@@ -98,6 +98,9 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
if (!REPORT_NULLABLE_METHODS_RETURNING_NOT_NULL) {
node.addContent(new Element("option").setAttribute("name", "REPORT_NULLABLE_METHODS_RETURNING_NOT_NULL").setAttribute("value", "false"));
}
if (!REPORT_UNCHECKED_OPTIONALS) {
node.addContent(new Element("option").setAttribute("name", "REPORT_UNCHECKED_OPTIONALS").setAttribute("value", "false"));
}
}
@Override
@@ -338,6 +341,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
reportOptionalOfNullableImprovements(holder, reportedAnchors, runner.getInstructions());
reportUncheckedOptionalGet(holder, visitor.getOptionalCalls(), visitor.getOptionalQualifiers());
if (REPORT_CONSTANT_REFERENCE_VALUES) {
reportConstantReferenceValues(holder, visitor, reportedAnchors);
@@ -348,6 +352,36 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
}
}
private void reportUncheckedOptionalGet(ProblemsHolder holder,
Map<PsiMethodCallExpression, ThreeState> calls,
List<PsiExpression> qualifiers) {
for (Map.Entry<PsiMethodCallExpression, ThreeState> entry : calls.entrySet()) {
ThreeState state = entry.getValue();
if (state == ThreeState.YES || state == ThreeState.UNSURE && !REPORT_UNCHECKED_OPTIONALS) {
continue;
}
PsiMethodCallExpression call = entry.getKey();
PsiMethod method = call.resolveMethod();
if (method == null) continue;
PsiClass optionalClass = method.getContainingClass();
if (optionalClass == null) continue;
if (state == ThreeState.NO) {
holder.registerProblem(getElementToHighlight(call),
InspectionsBundle.message("dataflow.message.optional.get.definitely.absent", optionalClass.getName()));
} else if (state == ThreeState.UNSURE) {
PsiExpression qualifier = PsiUtil.skipParenthesizedExprDown(call.getMethodExpression().getQualifierExpression());
if (qualifier instanceof PsiMethodCallExpression &&
qualifiers.stream().anyMatch(q -> PsiEquivalenceUtil.areElementsEquivalent(q, qualifier))) {
// Conservatively do not report methodCall().get() cases if methodCall().isPresent() was found in the same method
// without deep correspondence analysis
continue;
}
holder.registerProblem(getElementToHighlight(call),
InspectionsBundle.message("dataflow.message.optional.get.without.is.present", optionalClass.getName()));
}
}
}
private static void reportAlwaysReturnsNotNull(ProblemsHolder holder, PsiElement scope) {
if (!(scope.getParent() instanceof PsiMethod)) return;
@@ -895,6 +929,8 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
private final Map<Pair<NullabilityProblem, PsiElement>, StateInfo> myStateInfos = ContainerUtil.newHashMap();
private final Set<Instruction> myCCEInstructions = ContainerUtil.newHashSet();
private final Map<MethodCallInstruction, Boolean> myFailingCalls = new HashMap<>();
private final Map<PsiMethodCallExpression, ThreeState> myOptionalCalls = new HashMap<>();
private final List<PsiExpression> myOptionalQualifiers = new ArrayList<>();
private boolean myAlwaysReturnsNotNull = true;
@Override
@@ -912,6 +948,14 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
});
}
Map<PsiMethodCallExpression, ThreeState> getOptionalCalls() {
return myOptionalCalls;
}
List<PsiExpression> getOptionalQualifiers() {
return myOptionalQualifiers;
}
Collection<PsiCall> getAlwaysFailingCalls() {
return StreamEx.ofKeys(myFailingCalls, v -> v).map(MethodCallInstruction::getCallExpression).toList();
}
@@ -924,6 +968,20 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
public DfaInstructionState[] visitMethodCall(MethodCallInstruction instruction,
DataFlowRunner runner,
DfaMemoryState memState) {
PsiMethodCallExpression call = ObjectUtils.tryCast(instruction.getCallExpression(), PsiMethodCallExpression.class);
if (call != null) {
String methodName = call.getMethodExpression().getReferenceName();
PsiExpression qualifier = PsiUtil.skipParenthesizedExprDown(call.getMethodExpression().getQualifierExpression());
if (qualifier != null && TypeUtils.isOptional(qualifier.getType())) {
if ("isPresent".equals(methodName) && qualifier instanceof PsiMethodCallExpression) {
myOptionalQualifiers.add(qualifier);
}
else if (isOptionalGetMethodName(methodName)) {
ThreeState state = memState.checkOptional(memState.peek());
myOptionalCalls.merge(call, state, (s1, s2) -> s1 == s2 ? s1 : ThreeState.UNSURE);
}
}
}
DfaInstructionState[] states = super.visitMethodCall(instruction, runner, memState);
if (hasNonTrivialFailingContracts(instruction)) {
boolean allFail = Arrays.stream(states).allMatch(s -> s.getMemoryState().peek() == runner.getFactory().getConstFactory().getContractFail());
@@ -932,6 +990,10 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
return states;
}
private static boolean isOptionalGetMethodName(String name) {
return "get".equals(name) || "getAsDouble".equals(name) || "getAsInt".equals(name) || "getAsLong".equals(name);
}
private static boolean hasNonTrivialFailingContracts(MethodCallInstruction instruction) {
List<MethodContract> contracts = instruction.getContracts();
return !contracts.isEmpty() && contracts.stream().allMatch(DataFlowInstructionVisitor::isNonTrivialFailingContract);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -26,7 +26,6 @@ package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
@@ -286,14 +285,14 @@ public class DataFlowRunner {
for (PsiMethod method : nestedClass.getMethods()) {
PsiCodeBlock body = method.getBody();
if (body != null) {
myNestedClosures.putValue(body, createClosureState(state));
myNestedClosures.putValue(body, state.createClosureState());
}
}
for (PsiClassInitializer initializer : nestedClass.getInitializers()) {
myNestedClosures.putValue(initializer.getBody(), createClosureState(state));
myNestedClosures.putValue(initializer.getBody(), state.createClosureState());
}
for (PsiField field : nestedClass.getFields()) {
myNestedClosures.putValue(field, createClosureState(state));
myNestedClosures.putValue(field, state.createClosureState());
}
}
@@ -301,7 +300,7 @@ public class DataFlowRunner {
DfaMemoryState state = instructionState.getMemoryState();
PsiElement body = expr.getBody();
if (body != null) {
myNestedClosures.putValue(body, createClosureState(state));
myNestedClosures.putValue(body, state.createClosureState());
}
}
@@ -359,16 +358,4 @@ public class DataFlowRunner {
return Pair.create(trueSet, falseSet);
}
@NotNull
private static DfaMemoryStateImpl createClosureState(@NotNull DfaMemoryState memState) {
DfaMemoryStateImpl copy = (DfaMemoryStateImpl)memState.createCopy();
copy.flushFields();
Set<DfaVariableValue> vars = new HashSet<>(copy.getVariableStates().keySet());
for (DfaVariableValue value : vars) {
copy.flushDependencies(value);
}
copy.emptyStack();
return copy;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -34,6 +34,9 @@ public interface DfaMemoryState {
@NotNull
DfaMemoryState createCopy();
@NotNull
DfaMemoryState createClosureState();
DfaValue pop();
DfaValue peek();
void push(@NotNull DfaValue value);
@@ -53,6 +53,8 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
// dfa value id -> indices in myEqClasses list of the classes which contain the id (or wrapped)
private final TIntObjectHashMap<int[]> myIdToEqClassesIndices;
private final Stack<DfaValue> myStack;
// Closures which correspond to the stack top (do not track other closures for now)
private final List<DfaMemoryState> myStackTopClosures = new ArrayList<>();
private final TLongHashSet myDistinctClasses;
private final LinkedHashMap<DfaVariableValue,DfaVariableState> myVariableStates;
private final Map<DfaVariableValue,DfaVariableState> myDefaultVariableStates;
@@ -106,6 +108,24 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return new DfaMemoryStateImpl(this);
}
@NotNull
@Override
public DfaMemoryStateImpl createClosureState() {
DfaMemoryStateImpl copy = createCopy();
copy.flushFields();
Set<DfaVariableValue> vars = new HashSet<>(copy.getVariableStates().keySet());
for (DfaVariableValue value : vars) {
copy.flushDependencies(value);
}
copy.emptyStack();
myStackTopClosures.add(copy);
return copy;
}
List<DfaMemoryState> getStackTopClosures() {
return new ArrayList<>(myStackTopClosures);
}
public boolean equals(Object obj) {
if (obj == this) return true;
if (!(obj instanceof DfaMemoryStateImpl)) return false;
@@ -221,6 +241,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
@Override
public DfaValue pop() {
myCachedHash = null;
myStackTopClosures.clear();
return myStack.pop();
}
@@ -232,12 +253,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
@Override
public void push(@NotNull DfaValue value) {
myCachedHash = null;
myStackTopClosures.clear();
myStack.push(value);
}
@Override
public void emptyStack() {
myCachedHash = null;
myStackTopClosures.clear();
while (!myStack.isEmpty() && !(myStack.peek() instanceof DfaControlTransferValue)) {
myStack.pop();
}
@@ -1116,7 +1139,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
@Override
public boolean execute(int id, int[] set) {
DfaValue value = myFactory.getValue(id);
s.append(value + " -> " + Arrays.toString(set) + ", ");
s.append(value).append(" -> ").append(Arrays.toString(set)).append(", ");
return true;
}
});
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -42,6 +42,9 @@ import static com.intellij.psi.JavaTokenType.*;
* @author peter
*/
public class StandardInstructionVisitor extends InstructionVisitor {
private static final Set<String> OPTIONAL_METHOD_NAMES =
ContainerUtil.set("isPresent", "of", "ofNullable", "fromNullable", "empty", "absent",
"or", "orElseGet", "ifPresent", "map", "flatMap", "filter", "transform");
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.StandardInstructionVisitor");
private static final Object ANY_VALUE = new Object();
private final Set<BinopInstruction> myReachable = new THashSet<>();
@@ -180,13 +183,13 @@ public class StandardInstructionVisitor extends InstructionVisitor {
@Override
public DfaInstructionState[] visitMethodCall(final MethodCallInstruction instruction, final DataFlowRunner runner, final DfaMemoryState memState) {
DfaValue[] argValues = popCallArguments(instruction, runner, memState);
final DfaValue qualifier = popQualifier(instruction, runner, memState);
Set<DfaMemoryState> finalStates = ContainerUtil.newLinkedHashSet();
finalStates.addAll(handleOptionalMethods(instruction, runner, memState, qualifier, argValues));
finalStates.addAll(handleOptionalMethods(instruction, runner, memState));
if (finalStates.isEmpty()) {
DfaValue[] argValues = popCallArguments(instruction, runner, memState);
final DfaValue qualifier = popQualifier(instruction, runner, memState);
LinkedHashSet<DfaMemoryState> currentStates = ContainerUtil.newLinkedHashSet(memState);
if (argValues != null) {
for (MethodContract contract : instruction.getContracts()) {
@@ -219,54 +222,63 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
@NotNull
private static List<DfaMemoryState> handleOptionalMethods(MethodCallInstruction instruction,
DataFlowRunner runner,
DfaMemoryState memState,
DfaValue qualifierValue, @Nullable DfaValue[] argValues) {
private List<DfaMemoryState> handleOptionalMethods(MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
PsiMethodCallExpression call = ObjectUtils.tryCast(instruction.getCallExpression(), PsiMethodCallExpression.class);
if (call == null) return Collections.emptyList();
String methodName = call.getMethodExpression().getReferenceName();
if ("isPresent".equals(methodName)) {
PsiMethod method = call.resolveMethod();
if (method != null && TypeUtils.isOptional(method.getContainingClass())) {
ThreeState state = memState.checkOptional(qualifierValue);
if (methodName == null || !OPTIONAL_METHOD_NAMES.contains(methodName)) return Collections.emptyList();
PsiMethod method = call.resolveMethod();
if (method == null || !TypeUtils.isOptional(method.getContainingClass())) return Collections.emptyList();
List<DfaMemoryState> closures = ((DfaMemoryStateImpl)memState).getStackTopClosures();
DfaValue[] argValues = popCallArguments(instruction, runner, memState);
final DfaValue qualifier = popQualifier(instruction, runner, memState);
switch (methodName) {
case "isPresent": {
ThreeState state = memState.checkOptional(qualifier);
DfaConstValue.Factory constFactory = runner.getFactory().getConstFactory();
if (state == ThreeState.UNSURE) {
DfaMemoryState falseState = memState.createCopy();
memState.push(constFactory.getTrue());
memState.applyIsPresentCheck(true, qualifierValue);
memState.applyIsPresentCheck(true, qualifier);
falseState.push(constFactory.getFalse());
falseState.applyIsPresentCheck(false, qualifierValue);
falseState.applyIsPresentCheck(false, qualifier);
return Arrays.asList(memState, falseState);
}
else {
DfaValue result = state == ThreeState.YES ? constFactory.getTrue() : constFactory.getFalse();
memState.push(result);
return Collections.singletonList(memState);
memState.push(state == ThreeState.YES ? constFactory.getTrue() : constFactory.getFalse());
}
break;
}
}
if ("of".equals(methodName)) {
PsiMethod method = call.resolveMethod();
if (method != null && TypeUtils.isOptional(method.getContainingClass())) {
memState.push(runner.getFactory().getOptionalFactory().getOptional(true));
return Collections.singletonList(memState);
}
}
if (DfaOptionalSupport.resolveOfNullable(call) != null) {
if (argValues != null && argValues.length == 1 && memState.isNotNull(argValues[0])) {
memState.push(runner.getFactory().getOptionalFactory().getOptional(true));
return Collections.singletonList(memState);
}
}
if ("empty".equals(methodName) || "absent".equals(methodName)) {
PsiMethod method = call.resolveMethod();
if (method != null && TypeUtils.isOptional(method.getContainingClass())) {
case "of":
case "ofNullable":
case "fromNullable":
if ("of".equals(methodName) || (argValues != null && argValues.length == 1 && memState.isNotNull(argValues[0]))) {
memState.push(runner.getFactory().getOptionalFactory().getOptional(true));
} else {
memState.push(getMethodResultValue(instruction, qualifier, runner.getFactory()));
}
break;
case "empty":
case "absent":
memState.push(runner.getFactory().getOptionalFactory().getOptional(false));
return Collections.singletonList(memState);
}
break;
case "filter":
case "flatMap":
case "ifPresent":
case "map":
case "or":
case "orElseGet":
case "transform":
for (DfaMemoryState closure : closures) {
closure.applyIsPresentCheck(!methodName.startsWith("or"), qualifier);
}
memState.push(getMethodResultValue(instruction, qualifier, runner.getFactory()));
break;
default:
memState.push(getMethodResultValue(instruction, qualifier, runner.getFactory()));
break;
}
return Collections.emptyList();
return Collections.singletonList(memState);
}
@Nullable
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
package com.intellij.codeInspection.dataFlow.value;
public class DfaValue {
public abstract class DfaValue {
private final int myID;
protected final DfaValueFactory myFactory;
@@ -55,7 +55,7 @@ public class Java9ModuleExportsPackageToItselfInspection extends BaseJavaLocalIn
super.visitExportsStatement(statement);
PsiJavaModule javaModule = PsiTreeUtil.getParentOfType(statement, PsiJavaModule.class);
if (javaModule != null) {
String moduleName = javaModule.getModuleName();
String moduleName = javaModule.getName();
List<PsiJavaModuleReferenceElement> referenceElements = ContainerUtil.newArrayList(statement.getModuleReferences());
for (PsiJavaModuleReferenceElement referenceElement : referenceElements) {
if (moduleName.equals(referenceElement.getReferenceText())) {
@@ -173,7 +173,7 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn
return StreamEx.of(transitiveModules)
.filter(transitiveModule -> isReexported(currentModule, transitiveModule))
.map(transitiveModule -> transitiveModule.getModuleName())
.map(transitiveModule -> transitiveModule.getName())
.toSet();
}
@@ -204,7 +204,7 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn
PsiJavaParserFacade parserFacade = JavaPsiFacade.getInstance(currentModule.getProject()).getParserFacade();
for (String dependencyName : reexportedDependencies) {
PsiJavaModule tempModule =
parserFacade.createModuleFromText("module " + currentModule.getModuleName() + " { requires " + dependencyName + "; }");
parserFacade.createModuleFromText("module " + currentModule.getName() + " { requires " + dependencyName + "; }");
Iterable<PsiRequiresStatement> tempModuleRequires = tempModule.getRequires();
PsiRequiresStatement requiresStatement = tempModuleRequires.iterator().next();
currentModule.addAfter(requiresStatement, addingPlace);
@@ -37,7 +37,7 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule {
private List<RequiredModule> myRequiredModules;
public RefJavaModuleImpl(@NotNull PsiJavaModule javaModule, @NotNull RefManagerImpl manager) {
super(javaModule.getModuleName(), javaModule, manager);
super(javaModule.getName(), javaModule, manager);
myRefModule = manager.getRefModule(ModuleUtilCore.findModuleForPsiElement(javaModule));
}
@@ -91,7 +91,7 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule {
PsiJavaModule requiredModule = (PsiJavaModule)element;
Map<String, List<String>> packagesExportedByModule = getPackagesExportedByModule(requiredModule);
if (myRequiredModules == null) myRequiredModules = new ArrayList<>(1);
myRequiredModules.add(new RequiredModule(requiredModule.getModuleName(), packagesExportedByModule, statement.isPublic()));
myRequiredModules.add(new RequiredModule(requiredModule.getName(), packagesExportedByModule, statement.isPublic()));
}
}
}
@@ -110,7 +110,7 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule {
if (packageName != null && moduleElement instanceof PsiJavaModule) {
List<String> toModuleNames = myExportedPackageNames.get(packageName);
if (toModuleNames == emptyList) myExportedPackageNames.put(packageName, toModuleNames = new ArrayList<>(1));
toModuleNames.add(((PsiJavaModule)moduleElement).getModuleName());
toModuleNames.add(((PsiJavaModule)moduleElement).getName());
}
}
}
@@ -92,7 +92,7 @@ class JavaModuleCompletion {
if (!(statement instanceof PsiJavaModule)) {
PsiElement host = statement.getParent();
if (host instanceof PsiJavaModule) {
String hostName = ((PsiJavaModule)host).getModuleName();
String hostName = ((PsiJavaModule)host).getName();
Project project = context.getProject();
JavaModuleNameIndex index = JavaModuleNameIndex.getInstance();
GlobalSearchScope scope = ProjectScope.getAllScope(project);
@@ -324,7 +324,7 @@ public class MarkerType {
return null;
}
Comparator<PsiClass> comparator = PsiClassListCellRenderer.INSTANCE.getComparator();
Comparator<PsiClass> comparator = new PsiClassListCellRenderer().getComparator();
Arrays.sort(subclasses, comparator);
String start = DaemonBundle.message(aClass.isInterface() ? "interface.is.implemented.by.header" : "class.is.subclassed.by.header");
@@ -125,7 +125,7 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction {
final Project project = firstClass.getProject();
final JList list = new JBList(classes);
PsiElementListCellRenderer renderer = PsiClassListCellRenderer.INSTANCE;
PsiElementListCellRenderer renderer = new PsiClassListCellRenderer();
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(renderer);
final PopupChooserBuilder builder = new PopupChooserBuilder(list);
@@ -109,7 +109,7 @@ public class CreateInnerClassFromUsageFix extends CreateClassFromUsageBaseFix {
final Project project = classes[0].getProject();
final JList list = new JBList(classes);
PsiElementListCellRenderer renderer = PsiClassListCellRenderer.INSTANCE;
PsiElementListCellRenderer renderer = new PsiClassListCellRenderer();
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(renderer);
final PopupChooserBuilder builder = new PopupChooserBuilder(list);
@@ -99,7 +99,7 @@ public class PullAsAbstractUpFix extends LocalQuickFixAndIntentionActionOnPsiEle
pullUp(method, containingClass, classesToPullUp.iterator().next());
}
else if (editor != null) {
NavigationUtil.getPsiElementPopup(classesToPullUp.toArray(new PsiClass[classesToPullUp.size()]), PsiClassListCellRenderer.INSTANCE,
NavigationUtil.getPsiElementPopup(classesToPullUp.toArray(new PsiClass[classesToPullUp.size()]), new PsiClassListCellRenderer(),
"Choose super class",
new PsiElementProcessor<PsiClass>() {
@Override
@@ -44,6 +44,6 @@ public abstract class ChooseClassAndDoHighlightRunnable extends ChooseOneOrAllRu
@Override
protected PsiElementListCellRenderer<PsiClass> createRenderer() {
return PsiClassListCellRenderer.INSTANCE;
return new PsiClassListCellRenderer();
}
}
@@ -28,6 +28,7 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.FindSuperElementsHelper;
import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -62,7 +63,7 @@ public class ShowSiblingsAction extends ShowImplementationsAction {
final boolean isMethod = superElements[0] instanceof PsiMethod;
NavigatablePsiElement[] navigatablePsiElements = ContainerUtil.findAllAsArray(superElements, NavigatablePsiElement.class);
final JBPopup popup = PsiElementListNavigator.navigateOrCreatePopup(navigatablePsiElements, "Choose super " + (isMethod ? "method" : "class or interface"), "Super " + (isMethod ? "methods" : "classes/interfaces"),
isMethod ? new MethodCellRenderer(false) : PsiClassListCellRenderer.INSTANCE, null,
isMethod ? new MethodCellRenderer(false) : new PsiClassListCellRenderer(), null,
objects -> showSiblings(invokedByShortcut, project, editor, file, editor != null, (PsiElement)objects[0]));
if (popup != null) {
if (editor != null) {
@@ -178,9 +178,10 @@ public class ImplementAbstractMethodHandler {
}
private static class MyPsiElementListCellRenderer extends PsiElementListCellRenderer<PsiElement> {
private final PsiClassListCellRenderer myRenderer = new PsiClassListCellRenderer();
void sort(PsiElement[] result) {
final Comparator<PsiClass> comparator = PsiClassListCellRenderer.INSTANCE.getComparator();
final Comparator<PsiClass> comparator = myRenderer.getComparator();
Arrays.sort(result, (o1, o2) -> {
if (o1 instanceof PsiEnumConstant && o2 instanceof PsiEnumConstant) {
return ((PsiEnumConstant)o1).getName().compareTo(((PsiEnumConstant)o2).getName());
@@ -193,7 +194,7 @@ public class ImplementAbstractMethodHandler {
@Override
public String getElementText(PsiElement element) {
return element instanceof PsiClass ? PsiClassListCellRenderer.INSTANCE.getElementText((PsiClass)element)
return element instanceof PsiClass ? myRenderer.getElementText((PsiClass)element)
: ((PsiEnumConstant)element).getName();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -729,7 +729,7 @@ public class JavaDocInfoGenerator {
private void generateModuleJavaDoc(StringBuilder buffer, PsiJavaModule module, boolean generatePrologueAndEpilogue) {
if (generatePrologueAndEpilogue) generatePrologue(buffer);
buffer.append("<pre>module <b>").append(module.getModuleName()).append("</b></pre>");
buffer.append("<pre>module <b>").append(module.getName()).append("</b></pre>");
PsiDocComment comment = module.getDocComment();
if (comment != null) {
@@ -35,7 +35,7 @@ public class JavaGotoTargetRendererProvider implements GotoTargetRendererProvide
return new MethodCellRenderer(gotoData.hasDifferentNames());
}
else if (element instanceof PsiClass) {
return PsiClassListCellRenderer.INSTANCE;
return new PsiClassListCellRenderer();
}
else if (element instanceof PsiFunctionalExpression) {
return new PsiClassOrFunctionalExpressionListCellRenderer();
@@ -76,6 +76,7 @@ public class DataFlowInspection extends DataFlowInspectionBase {
private final JCheckBox myTreatUnknownMembersAsNullable;
private final JCheckBox myReportNullArguments;
private final JCheckBox myReportNullableMethodsReturningNotNull;
private final JCheckBox myReportUncheckedOptionals;
private OptionsPanel() {
super(new GridBagLayout());
@@ -151,6 +152,15 @@ public class DataFlowInspection extends DataFlowInspectionBase {
}
});
myReportUncheckedOptionals = new JCheckBox("Report Optional.get() calls without previous isPresent check");
myReportUncheckedOptionals.setSelected(REPORT_UNCHECKED_OPTIONALS);
myReportUncheckedOptionals.getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
REPORT_UNCHECKED_OPTIONALS = myReportUncheckedOptionals.isSelected();
}
});
gc.insets = JBUI.emptyInsets();
gc.gridy = 0;
add(mySuggestNullables, gc);
@@ -182,6 +192,9 @@ public class DataFlowInspection extends DataFlowInspectionBase {
gc.gridy++;
add(myReportNullableMethodsReturningNotNull, gc);
gc.gridy++;
add(myReportUncheckedOptionals, gc);
}
}
@@ -38,7 +38,6 @@ import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.pom.java.LanguageLevel
import com.intellij.profile.codeInspection.InspectionProjectProfileManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiJavaFile
@@ -47,15 +46,17 @@ import com.intellij.psi.util.PsiTreeUtil
import com.sun.tools.doclint.DocLint
import java.io.File
class JavadocHtmlLintAnnotator(private val manual: Boolean = false) :
class JavadocHtmlLintAnnotator() :
ExternalAnnotator<JavadocHtmlLintAnnotator.Info, JavadocHtmlLintAnnotator.Result>() {
data class Info(val file: PsiFile)
data class Anno(val row: Int, val col: Int, val error: Boolean, val message: String)
data class Result(val annotations: List<Anno>)
override fun getPairedBatchInspectionShortName() = JavadocHtmlLintInspection.SHORT_NAME
override fun collectInformation(file: PsiFile): Info? =
if (isJava8SourceFile(file) && "/**" in file.text && isToolEnabled(file)) Info(file) else null
if (isJava8SourceFile(file) && "/**" in file.text) Info(file) else null
override fun doAnnotate(collectedInfo: Info): Result? {
val file = collectedInfo.file.virtualFile!!
@@ -122,9 +123,6 @@ class JavadocHtmlLintAnnotator(private val manual: Boolean = false) :
file is PsiJavaFile && file.languageLevel.isAtLeast(LanguageLevel.JDK_1_8) &&
file.virtualFile != null && ProjectFileIndex.SERVICE.getInstance(file.project).isInSourceContent(file.virtualFile)
private fun isToolEnabled(file: PsiFile) =
manual || InspectionProjectProfileManager.getInstance(file.project).currentProfile.isToolEnabled(key.value, file)
private fun createTempFile(bytes: ByteArray): File {
val tempFile = FileUtil.createTempFile(File(PathManager.getTempPath()), "javadocHtmlLint", ".java")
tempFile.writeBytes(bytes)
@@ -15,23 +15,15 @@
*/
package com.intellij.codeInspection.javaDoc
import com.intellij.codeInspection.ExternalAnnotatorInspectionVisitor
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.codeInspection.SuppressQuickFix
import com.intellij.codeInspection.ex.PairedUnfairLocalInspectionTool
import com.intellij.codeInspection.ex.ExternalAnnotatorBatchInspection
import com.intellij.psi.PsiElement
class JavadocHtmlLintInspection : LocalInspectionTool(), PairedUnfairLocalInspectionTool {
class JavadocHtmlLintInspection : LocalInspectionTool(), ExternalAnnotatorBatchInspection {
companion object {
val SHORT_NAME = "JavadocHtmlLint"
}
private val annotator = lazy { JavadocHtmlLintAnnotator(true) }
override fun buildVisitor(holder: ProblemsHolder, onTheFly: Boolean) = ExternalAnnotatorInspectionVisitor(holder, annotator.value, onTheFly)
override fun getBatchSuppressActions(element: PsiElement?) = SuppressQuickFix.EMPTY_ARRAY
override fun getInspectionForBatchShortName() = SHORT_NAME
}
@@ -59,7 +59,8 @@ class TerminalBlock {
if(statements.length == 1 && statements[0] instanceof PsiBlockStatement) {
statements = ((PsiBlockStatement)statements[0]).getCodeBlock().getStatements();
} else if(statements.length == 1 && statements[0] instanceof PsiLabeledStatement) {
statements = new PsiStatement[] {((PsiLabeledStatement)statements[0]).getStatement()};
PsiStatement statement = ((PsiLabeledStatement)statements[0]).getStatement();
statements = statement == null ? PsiStatement.EMPTY_ARRAY : new PsiStatement[] {statement};
} else break;
}
myStatements = statements;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -66,7 +66,7 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider {
}
if (element instanceof PsiJavaModule) {
return ((PsiJavaModule)element).getModuleName();
return ((PsiJavaModule)element).getName();
}
if (element instanceof PsiJavaModuleReferenceElement) {
@@ -74,7 +74,7 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider {
if (reference != null) {
PsiElement target = reference.resolve();
if (target instanceof PsiJavaModule) {
return ((PsiJavaModule)target).getModuleName();
return ((PsiJavaModule)target).getName();
}
}
}
@@ -23,6 +23,7 @@ import javax.swing.*;
public class MethodCellRenderer extends PsiElementListCellRenderer<PsiMethod>{
private final boolean myShowMethodNames;
private final PsiClassListCellRenderer myClassListCellRenderer = new PsiClassListCellRenderer();
@PsiFormatUtil.FormatMethodOptions
private final int myOptions;
@@ -36,7 +37,7 @@ public class MethodCellRenderer extends PsiElementListCellRenderer<PsiMethod>{
public String getElementText(PsiMethod element) {
final PsiNamedElement container = fetchContainer(element);
String text = container instanceof PsiClass ? PsiClassListCellRenderer.INSTANCE.getElementText((PsiClass)container) : container.getName();
String text = container instanceof PsiClass ? myClassListCellRenderer.getElementText((PsiClass)container) : container.getName();
if (myShowMethodNames) {
text += "."+PsiFormatUtil.formatMethod(element, PsiSubstitutor.EMPTY, myOptions, PsiFormatUtilBase.SHOW_TYPE);
}
@@ -57,6 +58,6 @@ public class MethodCellRenderer extends PsiElementListCellRenderer<PsiMethod>{
}
public int getIconFlags() {
return PsiClassListCellRenderer.INSTANCE.getIconFlags();
return myClassListCellRenderer.getIconFlags();
}
}
@@ -26,6 +26,7 @@ import com.intellij.psi.util.PsiFormatUtilBase;
import javax.swing.*;
public class MethodOrFunctionalExpressionCellRenderer extends PsiElementListCellRenderer<NavigatablePsiElement> {
private final PsiClassListCellRenderer myClassListCellRenderer = new PsiClassListCellRenderer();
private final MethodCellRenderer myMethodCellRenderer;
public MethodOrFunctionalExpressionCellRenderer(boolean showMethodNames) {
@@ -50,6 +51,6 @@ public class MethodOrFunctionalExpressionCellRenderer extends PsiElementListCell
}
public int getIconFlags() {
return PsiClassListCellRenderer.INSTANCE.getIconFlags();
return myClassListCellRenderer.getIconFlags();
}
}
@@ -20,6 +20,10 @@ import com.intellij.psi.presentation.java.ClassPresentationUtil;
import org.jetbrains.annotations.Nullable;
public class PsiClassListCellRenderer extends PsiElementListCellRenderer<PsiClass> {
/**
* Should not be used, as it can result in memory leaks
*/
@Deprecated
public static final PsiClassListCellRenderer INSTANCE = new PsiClassListCellRenderer();
@Override
@@ -384,7 +384,7 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
VirtualFile file = PsiImplUtil.getModuleVirtualFile(module);
generateOrderEntryInfo(sb, file, module.getProject());
sb.append(LangBundle.message("java.terms.module")).append(' ').append(module.getModuleName());
sb.append(LangBundle.message("java.terms.module")).append(' ').append(module.getName());
return sb.toString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -194,7 +194,7 @@ public class JavaFindUsagesProvider implements FindUsagesProvider {
return element.getText();
}
if (element instanceof PsiJavaModule) {
return ((PsiJavaModule)element).getModuleName();
return ((PsiJavaModule)element).getName();
}
return "";
@@ -1529,7 +1529,7 @@ public class ExtractMethodProcessor implements MatchProvider {
if (classes.size() > 1) {
final PsiClass[] psiClasses = classes.keySet().toArray(new PsiClass[classes.size()]);
final PsiClass preselection = AnonymousTargetClassPreselectionUtil.getPreselection(classes.keySet(), psiClasses[0]);
NavigationUtil.getPsiElementPopup(psiClasses, PsiClassListCellRenderer.INSTANCE, "Choose Destination Class", processor, preselection)
NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), "Choose Destination Class", processor, preselection)
.showInBestPositionFor(myEditor);
return true;
}
@@ -134,7 +134,7 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
}
else if (!classes.isEmpty()){
PsiClass selection = AnonymousTargetClassPreselectionUtil.getPreselection(classes, myParentClass);
NavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), PsiClassListCellRenderer.INSTANCE,
NavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), new PsiClassListCellRenderer(),
"Choose class to introduce " + (myIsConstant ? "constant" : "field"),
new PsiElementProcessor<PsiClass>() {
@Override
@@ -94,7 +94,7 @@ public abstract class LocalToFieldHandler {
final boolean isStatic = tempIsStatic;
final PsiClass firstClass = classes.get(0);
final PsiClass preselection = AnonymousTargetClassPreselectionUtil.getPreselection(classes, firstClass);
NavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), PsiClassListCellRenderer.INSTANCE, "Choose class to introduce " + (myIsConstant ? "constant" : "field"), new PsiElementProcessor<PsiClass>() {
NavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), new PsiClassListCellRenderer(), "Choose class to introduce " + (myIsConstant ? "constant" : "field"), new PsiElementProcessor<PsiClass>() {
@Override
public boolean execute(@NotNull PsiClass aClass) {
AnonymousTargetClassPreselectionUtil.rememberSelection(aClass, aClass);
@@ -586,7 +586,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase {
final PsiType returnType = emptyMethod.getReturnType();
LOG.assertTrue(returnType != null);
final String title = "Choose Applicable Functional Interface: " + methodSignature + " -> " + returnType.getPresentableText();
NavigationUtil.getPsiElementPopup(psiClasses, PsiClassListCellRenderer.INSTANCE, title,
NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), title,
new PsiElementProcessor<PsiClass>() {
@Override
public boolean execute(@NotNull PsiClass psiClass) {
@@ -85,7 +85,7 @@ public class GenerateMissedTestsAction extends PsiElementBaseIntentionAction {
}
final JBList list = new JBList(testClasses);
list.setCellRenderer(PsiClassListCellRenderer.INSTANCE);
list.setCellRenderer(new PsiClassListCellRenderer());
JBPopupFactory.getInstance().createListPopupBuilder(list)
.setItemChoosenCallback(() -> generateMissedTests((PsiClass)list.getSelectedValue(), srcClass, editor))
.setTitle("Choose Test")
@@ -22,14 +22,14 @@ import org.jetbrains.annotations.NotNull;
*
* @since 2016.3
*/
public interface PsiJavaModule extends NavigatablePsiElement, PsiNamedElement, PsiJavaDocumentedElement {
public interface PsiJavaModule extends NavigatablePsiElement, PsiNameIdentifierOwner, PsiJavaDocumentedElement {
String MODULE_INFO_CLASS = "module-info";
String MODULE_INFO_FILE = MODULE_INFO_CLASS + ".java";
String MODULE_INFO_CLS_FILE = MODULE_INFO_CLASS + ".class";
String JAVA_BASE = "java.base";
@NotNull PsiJavaModuleReferenceElement getNameElement();
@NotNull String getModuleName();
@Override @NotNull PsiJavaModuleReferenceElement getNameIdentifier();
@Override @NotNull String getName();
@NotNull Iterable<PsiRequiresStatement> getRequires();
@NotNull Iterable<PsiPackageAccessibilityStatement> getExports();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -16,27 +16,26 @@
package com.intellij.psi;
import org.intellij.lang.annotations.MagicConstant;
import org.jetbrains.annotations.NonNls;
/**
* Provides a list of possible modifier keywords for Java classes, methods and fields.
*/
public interface PsiModifier {
@NonNls String PUBLIC = "public";
@NonNls String PROTECTED = "protected";
@NonNls String PRIVATE = "private";
@NonNls String PACKAGE_LOCAL = "packageLocal";
@NonNls String STATIC = "static";
@NonNls String ABSTRACT = "abstract";
@NonNls String FINAL = "final";
@NonNls String NATIVE = "native";
@NonNls String SYNCHRONIZED = "synchronized";
@NonNls String STRICTFP = "strictfp";
@NonNls String TRANSIENT = "transient";
@NonNls String VOLATILE = "volatile";
@NonNls String DEFAULT = "default";
String PUBLIC = "public";
String PROTECTED = "protected";
String PRIVATE = "private";
String PACKAGE_LOCAL = "packageLocal";
String STATIC = "static";
String ABSTRACT = "abstract";
String FINAL = "final";
String NATIVE = "native";
String SYNCHRONIZED = "synchronized";
String STRICTFP = "strictfp";
String TRANSIENT = "transient";
String VOLATILE = "volatile";
String DEFAULT = "default";
@NonNls String[] MODIFIERS = {
String[] MODIFIERS = {
PUBLIC, PROTECTED, PRIVATE, STATIC, ABSTRACT, FINAL, NATIVE, SYNCHRONIZED, STRICTFP, TRANSIENT, VOLATILE, DEFAULT
};
@@ -44,4 +43,4 @@ public interface PsiModifier {
PUBLIC, PROTECTED, PRIVATE, STATIC, ABSTRACT, FINAL, NATIVE, SYNCHRONIZED, STRICTFP, TRANSIENT, VOLATILE, DEFAULT, PACKAGE_LOCAL
})
@interface ModifierConstant { }
}
}
@@ -18,6 +18,7 @@ package com.intellij.psi;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.PackageDirectoryCache;
import com.intellij.openapi.util.LowMemoryWatcher;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -52,7 +53,7 @@ public abstract class NonClasspathClassFinder extends PsiElementFinder {
private final PsiManager myManager;
private final String[] myFileExtensions;
public NonClasspathClassFinder(Project project, String... fileExtensions) {
public NonClasspathClassFinder(@NotNull Project project, @NotNull String... fileExtensions) {
myProject = project;
myManager = PsiManager.getInstance(myProject);
myFileExtensions = ArrayUtil.append(fileExtensions, "class");
@@ -63,6 +64,12 @@ public abstract class NonClasspathClassFinder extends PsiElementFinder {
clearCache();
}
});
LowMemoryWatcher.register(new Runnable() {
@Override
public void run() {
clearCache();
}
}, project);
}
@NotNull
@@ -483,9 +483,12 @@ class ConstantExpressionVisitor extends JavaElementVisitor implements PsiConstan
else if (tokenType == JavaTokenType.TILDE) {
if (operandValue instanceof Character) operandValue = Integer.valueOf(((Character)operandValue).charValue());
if (isIntegral(operandValue)) {
value = operandValue instanceof Long
? Long.valueOf(~((Number)operandValue).longValue())
: Integer.valueOf(~((Number)operandValue).intValue());
if (operandValue instanceof Long) {
value = Long.valueOf(~((Number)operandValue).longValue());
}
else {
value = Integer.valueOf(~((Number)operandValue).intValue());
}
}
}
else if (tokenType == JavaTokenType.EXCL) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -370,7 +370,6 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub>
}
return CachedValuesManager.getCachedValue(this, new CachedValueProvider<PsiElement>() {
@Nullable
@Override
public Result<PsiElement> compute() {
PsiElement target = JavaPsiImplementationHelper.getInstance(getProject()).getClsFileNavigationElement(ClsFileImpl.this);
@@ -41,18 +41,6 @@ public class ClsJavaModuleImpl extends ClsRepositoryPsiElement<PsiJavaModuleStub
myReference = new ClsJavaModuleReferenceElementImpl(this, stub.getName());
}
@NotNull
@Override
public PsiJavaModuleReferenceElement getNameElement() {
return myReference;
}
@NotNull
@Override
public String getModuleName() {
return myReference.getReferenceText();
}
@NotNull
@Override
public Iterable<PsiRequiresStatement> getRequires() {
@@ -85,7 +73,7 @@ public class ClsJavaModuleImpl extends ClsRepositoryPsiElement<PsiJavaModuleStub
@Override
public void appendMirrorText(int indentLevel, @NotNull StringBuilder buffer) {
buffer.append("module ").append(getModuleName()).append(" {\n");
buffer.append("module ").append(getName()).append(" {\n");
int newIndentLevel = indentLevel + getIndentSize();
@@ -106,7 +94,7 @@ public class ClsJavaModuleImpl extends ClsRepositoryPsiElement<PsiJavaModuleStub
PsiJavaModule mirror = SourceTreeToPsiMap.treeToPsiNotNull(element);
setMirrorCheckingType(element, JavaElementType.MODULE);
setMirror(getNameElement(), mirror.getNameElement());
setMirror(getNameIdentifier(), mirror.getNameIdentifier());
setMirrors(newArrayList(getStub().getChildrenByType(JavaElementType.REQUIRES_STATEMENT, PsiRequiresStatement.EMPTY_ARRAY)),
newArrayList(mirror.getRequires()));
@@ -115,9 +103,16 @@ public class ClsJavaModuleImpl extends ClsRepositoryPsiElement<PsiJavaModuleStub
newArrayList(mirror.getExports()));
}
@NotNull
@Override
public PsiJavaModuleReferenceElement getNameIdentifier() {
return myReference;
}
@NotNull
@Override
public String getName() {
return getModuleName();
return myReference.getReferenceText();
}
@Override
@@ -139,7 +134,7 @@ public class ClsJavaModuleImpl extends ClsRepositoryPsiElement<PsiJavaModuleStub
@NotNull
@Override
public PsiElement getNavigationElement() {
return getNameElement();
return getNameIdentifier();
}
@Override
@@ -154,6 +149,6 @@ public class ClsJavaModuleImpl extends ClsRepositoryPsiElement<PsiJavaModuleStub
@Override
public String toString() {
return "PsiJavaModule:" + getModuleName();
return "PsiJavaModule:" + getName();
}
}
@@ -55,18 +55,6 @@ public class LightJavaModule extends LightElement implements PsiJavaModule {
return null;
}
@NotNull
@Override
public PsiJavaModuleReferenceElement getNameElement() {
return myRefElement;
}
@NotNull
@Override
public String getModuleName() {
return myRefElement.getReferenceText();
}
@NotNull
@Override
public Iterable<PsiRequiresStatement> getRequires() {
@@ -97,9 +85,16 @@ public class LightJavaModule extends LightElement implements PsiJavaModule {
return Collections.emptyList();
}
@NotNull
@Override
public PsiJavaModuleReferenceElement getNameIdentifier() {
return myRefElement;
}
@NotNull
@Override
public String getName() {
return getModuleName();
return myRefElement.getReferenceText();
}
@Override
@@ -125,12 +120,12 @@ public class LightJavaModule extends LightElement implements PsiJavaModule {
@Override
public int hashCode() {
return getModuleName().hashCode() * 31 + getManager().hashCode();
return getName().hashCode() * 31 + getManager().hashCode();
}
@Override
public String toString() {
return "PsiJavaModule:" + getModuleName();
return "PsiJavaModule:" + getName();
}
private static class LightJavaModuleReferenceElement extends LightElement implements PsiJavaModuleReferenceElement {
@@ -54,24 +54,6 @@ public class PsiJavaModuleImpl extends JavaStubPsiElement<PsiJavaModuleStub> imp
super(node);
}
@NotNull
@Override
public PsiJavaModuleReferenceElement getNameElement() {
return PsiTreeUtil.getRequiredChildOfType(this, PsiJavaModuleReferenceElement.class);
}
@NotNull
@Override
public String getModuleName() {
PsiJavaModuleStub stub = getGreenStub();
if (stub != null) {
return stub.getName();
}
else {
return getNameElement().getReferenceText();
}
}
@NotNull
@Override
public Iterable<PsiRequiresStatement> getRequires() {
@@ -120,16 +102,29 @@ public class PsiJavaModuleImpl extends JavaStubPsiElement<PsiJavaModuleStub> imp
return psiTraverser().children(this).filter(PsiProvidesStatement.class);
}
@NotNull
@Override
public PsiJavaModuleReferenceElement getNameIdentifier() {
return PsiTreeUtil.getRequiredChildOfType(this, PsiJavaModuleReferenceElement.class);
}
@NotNull
@Override
public String getName() {
return getModuleName();
PsiJavaModuleStub stub = getGreenStub();
if (stub != null) {
return stub.getName();
}
else {
return getNameIdentifier().getReferenceText();
}
}
@Override
public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
PsiElementFactory factory = PsiElementFactory.SERVICE.getInstance(getProject());
PsiJavaModuleReferenceElement newName = factory.createModuleFromText("module " + name + " {}").getNameElement();
getNameElement().replace(newName);
PsiJavaModuleReferenceElement newName = factory.createModuleFromText("module " + name + " {}").getNameIdentifier();
getNameIdentifier().replace(newName);
return this;
}
@@ -147,7 +142,7 @@ public class PsiJavaModuleImpl extends JavaStubPsiElement<PsiJavaModuleStub> imp
@NotNull
@Override
public PsiElement getNavigationElement() {
return getNameElement();
return getNameIdentifier();
}
@Override
@@ -162,6 +157,6 @@ public class PsiJavaModuleImpl extends JavaStubPsiElement<PsiJavaModuleStub> imp
@Override
public String toString() {
return "PsiJavaModule:" + getModuleName();
return "PsiJavaModule:" + getName();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -67,7 +67,7 @@ public class PsiJavaModuleReference extends PsiReferenceBase.Poly<PsiJavaModuleR
throw new IncorrectOperationException(JavaCoreBundle.message("psi.error.attempt.to.edit.class.file", element.getContainingFile()));
}
PsiElementFactory factory = PsiElementFactory.SERVICE.getInstance(element.getProject());
PsiJavaModuleReferenceElement newElement = factory.createModuleFromText("module " + newName + " {}").getNameElement();
PsiJavaModuleReferenceElement newElement = factory.createModuleFromText("module " + newName + " {}").getNameIdentifier();
return element.replace(newElement);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -36,10 +36,9 @@ public class JavaModulePresentationProvider implements ItemPresentationProvider<
@Override
public ItemPresentation getPresentation(@NotNull final PsiJavaModule item) {
return new ItemPresentation() {
@Nullable
@Override
public String getPresentableText() {
return item.getModuleName();
return item.getName();
}
@Nullable
@@ -0,0 +1,24 @@
import java.util.function.Function;
class Test {
public static void main(Builder<Beta> gammaBuilder) {
<error descr="Inferred type 'B' for type parameter 'B' is not within its bound; should extend 'Test.Builder<Test.Alfa>'">a(Test::c, name -> gammaBuilder)</error>;
}
private static <T extends Alfa, B extends Builder<T>> void a(final Function<B, String> f1,
final Function<String, B> f2) {
}
private static String c(final Builder<? extends Beta> builder) {
return "";
}
static class Alfa {}
private static class Beta extends Alfa {}
static class Builder<T> {}
}
@@ -0,0 +1,11 @@
// "Fix all 'Loop can be collapsed with Stream API' problems in file" "false"
import java.util.List;
public class Main {
void test(List<String> list) {
for(String l : li<caret>st) {
TEST:
}
}
}
@@ -13,10 +13,65 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.Optional;
import java.util.*;
class OptionalWithoutIsPresent {
void testSimple(Optional<String> o, OptionalDouble od, OptionalInt oi, OptionalLong ol) {
System.out.println(o.<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>());
System.out.println(oi.<warning descr="'OptionalInt.getAsInt()' without 'isPresent()' check">getAsInt</warning>());
System.out.println(ol.<warning descr="'OptionalLong.getAsLong()' without 'isPresent()' check">getAsLong</warning>());
System.out.println(od.<warning descr="'OptionalDouble.getAsDouble()' without 'isPresent()' check">getAsDouble</warning>());
}
{
System.out.println(getIntegerOptional().<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>());
}
void testWhile() {
Optional<String> o = Optional.empty();
while (!o.isPresent()) {
o = Optional.of("");
}
System.out.println(o.get());
}
void testWhile2() {
Optional<Integer> o = getIntegerOptional();
while (o.isPresent()) {
System.out.println(o.get());
}
}
public void testPolyadicExpression(Optional<String> value) {
boolean flag = value.isPresent() && "Yes".equals(value.get());
}
boolean testPolyadicExpression2(Optional<String> o) {
return !o.isPresent() || o.get().equals("j");
}
String testPolyadicExpression3() {
Optional<String> o = getOptional();
if (o == null || !o.isPresent()) {
return "";
}
return o.get();
}
void testNested(Optional<String> opt, String action) {
if (!opt.isPresent()) {
throw new IllegalArgumentException();
}
switch (action) {
case "case":
System.out.println(opt.get());
break;
default:
System.err.println(opt.get());
}
}
void m(Optional<Integer> maybe) {
if (!!!maybe.isPresent()) {
maybe = getIntegerOptional();
@@ -29,9 +84,9 @@ class OptionalWithoutIsPresent {
maybe = Optional.empty();
System.out.println(maybe.<warning descr="'Optional.get()' will definitely fail as Optional is empty here">get</warning>());
}
boolean b = ((maybe.isPresent())) && maybe.get() == 1;
boolean c = (!maybe.isPresent()) || maybe.get() == 1;
Integer value = !maybe.isPresent() ? 0 : maybe.get();
boolean b = <warning descr="Condition '((maybe.isPresent()))' is always 'false'">((maybe.isPresent()))</warning> && maybe.get() == 1;
boolean c = <warning descr="Condition '(!maybe.isPresent())' is always 'true'">(!maybe.isPresent())</warning> || maybe.get() == 1;
Integer value = <warning descr="Condition '!maybe.isPresent()' is always 'true'">!maybe.isPresent()</warning> ? 0 : maybe.get();
}
Optional<Integer> getIntegerOptional() {
@@ -42,7 +97,7 @@ class OptionalWithoutIsPresent {
Optional<String> optional = Optional.empty();
final boolean present = optional.isPresent();
// optional = Optional.empty();
if (present) {
if (<warning descr="Condition 'present' is always 'false'">present</warning>) {
final String string = optional.get();
System.out.println(string);
}
@@ -52,7 +107,7 @@ class OptionalWithoutIsPresent {
Optional<String> optional = Optional.empty();
final boolean present = optional.isPresent();
optional = Optional.empty();
if (present) {
if (<warning descr="Condition 'present' is always 'false'">present</warning>) {
final String string = optional.get();
System.out.println(string);
}
@@ -101,7 +156,7 @@ class OptionalWithoutIsPresent {
private void checkAsserts2() {
Optional<String> o3 = Optional.empty();
org.testng.Assert.assertTrue(o3.isPresent());
org.testng.Assert.<warning descr="The call to assertTrue always fails, according to its method contracts">assertTrue</warning>(o3.isPresent());
System.out.println(o3.get());
}
@@ -131,16 +186,16 @@ class OptionalWithoutIsPresent {
private void checkOfNullable(String value) {
System.out.println(Optional.ofNullable(value).<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>());
System.out.println(Optional.ofNullable(value+"a").get());
System.out.println(Optional.ofNullable("xyz").get());
System.out.println(Optional.ofNullable(<warning descr="Passing a non-null argument to 'Optional'">value+"a"</warning>).get());
System.out.println(Optional.ofNullable(<warning descr="Passing a non-null argument to 'Optional'">"xyz"</warning>).get());
}
public static String demo() {
Optional<String> holder = Optional.empty();
if (! holder.isPresent()) {
if (<warning descr="Condition '! holder.isPresent()' is always 'true'">! holder.isPresent()</warning>) {
holder = Optional.of("hello world");
if (!holder.isPresent()) {
if (<warning descr="Condition '!holder.isPresent()' is always 'false'">!holder.isPresent()</warning>) {
return null;
}
}
@@ -171,9 +226,10 @@ class OptionalWithoutIsPresent {
return Optional.empty();
}
//void order(Optional<String> order) {
// order.ifPresent(o -> System.out.println(order.get()));
//}
void order(Optional<String> order, boolean b) {
order.ifPresent(o -> System.out.println(order.get()));
System.out.println(order.orElseGet(() -> order.<warning descr="'Optional.get()' will definitely fail as Optional is empty here">get</warning>().trim()));
}
public static void two(Optional<Object> o1,Optional<Object> o2) {
if (!o1.isPresent() && !o2.isPresent()) {
@@ -210,7 +266,7 @@ class OptionalWithoutIsPresent {
opt2.get();
}
static final class Range {
class Range {
Optional<Integer> min = Optional.of(1);
Optional<Integer> max = Optional.of(2);
@@ -243,7 +299,7 @@ class OptionalWithoutIsPresent {
}
void shortIf(Optional<String> o) {
if (true || o.isPresent()) {
if (<warning descr="Condition 'true || o.isPresent()' is always 'true'">true || o.isPresent()</warning>) {
o.<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>();
}
}
@@ -257,6 +313,25 @@ class OptionalWithoutIsPresent {
}
String f(Optional<String> optional, Optional<String> opt2) {
return optional.isPresent() ? opt2.<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>() : null;
return optional.isPresent() ? opt2.<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>() : "";
}
void guavaTest(com.google.common.base.Optional<String> opt, String s) {
System.out.println(opt.<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>());
if(opt.isPresent()) {
System.out.println(opt.get());
}
opt = com.google.common.base.Optional.fromNullable(s);
if(opt.isPresent()) {
System.out.println(opt.get());
}
opt = com.google.common.base.Optional.of(s);
if(<warning descr="Condition 'opt.isPresent()' is always 'true'">opt.isPresent()</warning>) {
System.out.println(opt.get());
}
opt = com.google.common.base.Optional.absent();
if(<warning descr="Condition 'opt.isPresent()' is always 'false'">opt.isPresent()</warning>) {
System.out.println(opt.get());
}
}
}
@@ -517,6 +517,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testApplicabilityErrorVisibleWhenConstraintsFromFunctionalExpressionsProvideValidSubstitutor() {
doTest();
}
public void testMethodReferenceSecondSearchDontInfluenceTopSiteSubstitutor() throws Exception {
doTest();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -18,18 +18,29 @@ package com.intellij.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInspection.dataFlow.DataFlowInspection;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Disposer;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
private static final DefaultLightProjectDescriptor PROJECT_DESCRIPTOR = new DefaultLightProjectDescriptor() {
@Override
public Sdk getSdk() {
return PsiTestUtil.addJdkAnnotations(IdeaTestUtil.getMockJdk18());
}
};
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_8;
return PROJECT_DESCRIPTOR;
}
@Override
@@ -46,8 +57,30 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
public void testNullableVoidLambda() { doTest(); }
public void testNullableForeachVariable() { doTestWithCustomAnnotations(); }
public void testGenericParameterNullity() { doTestWithCustomAnnotations(); }
public void testOptionalOfNullable() { doTest(); }
public void testOptionalIsPresent() { doTest(); }
public void testOptionalGetWithoutIsPresent() {
myFixture.addClass("package org.junit;" +
"public class Assert {" +
" public static void assertTrue(boolean b) {}" +
"}");
myFixture.addClass("package org.testng;" +
"public class Assert {" +
" public static void assertTrue(boolean b) {}" +
"}");
myFixture.addClass("package com.google.common.base;\n" +
"\n" +
"public abstract class Optional<T> {\n" +
" public static <T> Optional<T> absent() {}\n" +
" public static <T> Optional<T> of(T ref) {}\n" +
" public static <T> Optional<T> fromNullable(T ref) {}\n" +
" public abstract T get();\n" +
" public abstract boolean isPresent();\n" +
"}");
doTest();
}
public void testPrimitiveInVoidLambda() { doTest(); }
public void testNotNullLambdaParameter() { doTest(); }
public void testNotNullOptionalLambdaParameter() { doTest(); }
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -423,7 +423,7 @@ public class ClsPsiTest extends LightIdeaTestCase {
PsiJavaModule module = file.getModuleDeclaration();
assertNotNull(module);
assertEquals("M.N", module.getModuleName());
assertEquals("M.N", module.getName());
assertNull(file.getPackageStatement());
assertEquals(0, file.getClasses().length);
@@ -37,4 +37,13 @@ public class ConstantEvaluatorTest extends LightCodeInsightFixtureTestCase {
assertEquals(MyEnum.Foo, result);
}
public void testPrefixExpressionEvaluation() throws Exception {
PsiJavaFile file = (PsiJavaFile)myFixture.configureByText("A.java", "class A {public static final int VALUE = ~0 >>> 1;}");
PsiClass aClass = file.getClasses()[0];
PsiField vField = aClass.getFields()[0];
Object result = JavaPsiFacade.getInstance(getProject()).getConstantEvaluationHelper().computeConstantExpression(vField.getInitializer());
assertEquals(2147483647, result);
}
}
@@ -76,4 +76,14 @@ public abstract class ExternalAnnotator<InitialInfoType, AnnotationResultType> {
*/
public void apply(@NotNull PsiFile file, AnnotationResultType annotationResult, @NotNull AnnotationHolder holder) {
}
/**
* Return inspection which should run in batch mode.
* When inspection with short name is disabled, then annotator won't run in the editor via {@link com.intellij.codeInsight.daemon.impl.ExternalToolPass}.
* Implementing {@link com.intellij.codeInspection.ex.ExternalAnnotatorBatchInspection} and extending {@link com.intellij.codeInspection.LocalInspectionTool} would
* provide implementation for a batch tool which would run without read action, according to the {@link #doAnnotate(Object)} documentation
*/
public String getPairedBatchInspectionShortName() {
return null;
}
}
@@ -21,6 +21,7 @@ import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationSession;
import com.intellij.lang.annotation.ExternalAnnotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
@@ -58,21 +59,23 @@ public class ExternalAnnotatorInspectionVisitor extends PsiElementVisitor {
public static <Init,Result> ProblemDescriptor[] checkFileWithExternalAnnotator(@NotNull PsiFile file,
@NotNull InspectionManager manager,
boolean isOnTheFly,
@NotNull ExternalAnnotator<Init,Result> annotator) {
@NotNull ExternalAnnotator<Init, Result> annotator) {
if (isOnTheFly) {
// ExternalAnnotator does this work
return ProblemDescriptor.EMPTY_ARRAY;
}
Init info = annotator.collectInformation(file);
Init info = ReadAction.compute(() -> annotator.collectInformation(file));
if (info != null) {
Result annotationResult = annotator.doAnnotate(info);
if (annotationResult == null) {
return ProblemDescriptor.EMPTY_ARRAY;
}
AnnotationHolderImpl annotationHolder = new AnnotationHolderImpl(new AnnotationSession(file));
annotator.apply(file, annotationResult, annotationHolder);
return convertToProblemDescriptors(annotationHolder, manager, file);
return ReadAction.compute(() -> {
AnnotationHolderImpl annotationHolder = new AnnotationHolderImpl(new AnnotationSession(file));
annotator.apply(file, annotationResult, annotationHolder);
return convertToProblemDescriptors(annotationHolder, manager, file);
});
}
return ProblemDescriptor.EMPTY_ARRAY;
}
@@ -0,0 +1,57 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInspection.ex;
import com.intellij.codeInspection.ExternalAnnotatorInspectionVisitor;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.lang.ExternalLanguageAnnotators;
import com.intellij.lang.Language;
import com.intellij.lang.annotation.ExternalAnnotator;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Set;
public interface ExternalAnnotatorBatchInspection extends PairedUnfairLocalInspectionTool {
@NotNull
String getShortName();
@NotNull
@Override
default String getInspectionForBatchShortName() {
return getShortName();
}
default ProblemDescriptor[] checkFile(PsiFile file, InspectionManager manager) {
final String shortName = getShortName();
final FileViewProvider viewProvider = file.getViewProvider();
final Set<Language> relevantLanguages = viewProvider.getLanguages();
for (Language language : relevantLanguages) {
PsiFile psiRoot = viewProvider.getPsi(language);
final List<ExternalAnnotator> externalAnnotators = ExternalLanguageAnnotators.allForFile(language, psiRoot);
for (ExternalAnnotator annotator : externalAnnotators) {
if (shortName.equals(annotator.getPairedBatchInspectionShortName())) {
return ExternalAnnotatorInspectionVisitor.checkFileWithExternalAnnotator(file, manager, false, annotator);
}
}
}
return ProblemDescriptor.EMPTY_ARRAY;
}
}
@@ -3,20 +3,21 @@ package com.intellij.configurationStore
import com.intellij.openapi.components.BaseState
import com.intellij.testFramework.assertions.Assertions.assertThat
import com.intellij.util.loadElement
import com.intellij.util.xmlb.XmlSerializer
import com.intellij.util.xmlb.annotations.Attribute
import org.junit.Test
private class AState : BaseState() {
internal class AState : BaseState() {
@get:Attribute("customName")
var languageLevel by storedProperty<String?>()
var property2 by storedProperty(0)
var floatProperty by storedProperty(0.3)
var nestedComplex by storedProperty<NestedState?>()
}
private class NestedState : BaseState() {
internal class NestedState : BaseState() {
var childProperty by storedProperty<String?>()
}
@@ -36,7 +37,7 @@ class StoredPropertyStateTest {
assertThat(state).isNotEqualTo(AState())
assertThat(XmlSerializer.serialize(state)).isEqualTo("""<AState customName="foo" />""")
assertThat(state.serialize()).isEqualTo("""<AState customName="foo" />""")
assertThat(loadElement("""<AState customName="foo" />""").deserialize(AState::class.java).languageLevel).isEqualTo("foo")
}
@@ -15,6 +15,7 @@
*/
package com.intellij.configurationStore.xml
import com.intellij.configurationStore.AState
import com.intellij.configurationStore.deserialize
import com.intellij.util.loadElement
import com.intellij.util.xmlb.annotations.MapAnnotation
@@ -38,6 +39,16 @@ class KotlinXmlSerializerTest {
</bean>""", data)
}
@Test fun floatProperty() {
val state = AState()
state.floatProperty = 3.4
doSerializerTest("""
<AState>
<option name="floatProperty" value="3.4" />
</AState>
""", state)
}
@Test fun nullInMap() {
@Tag("bean")
class Foo {
@@ -15,6 +15,7 @@
*/
package com.intellij.configurationStore.xml
import com.intellij.configurationStore.StoredPropertyStateTest
import com.intellij.configurationStore.deserialize
import com.intellij.configurationStore.serialize
import com.intellij.openapi.util.JDOMUtil
@@ -39,6 +40,7 @@ import java.util.*
XmlSerializerTest::class,
XmlSerializerMapTest::class,
XmlSerializerCollectionTest::class,
StoredPropertyStateTest::class,
KotlinXmlSerializerTest::class
)
class XmlSerializerTestSuite
@@ -240,7 +242,7 @@ internal class XmlSerializerTest {
bean.INT_V = 987
bean.STRING_V = "1234"
val element = bean.serialize(null)
val element = bean.serialize()
val node = element.children.get(0)
element.removeContent(node)
@@ -642,7 +644,7 @@ internal class XmlSerializerTest {
private val XML_PREFIX = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
internal fun assertSerializer(bean: Any, expected: String, filter: SerializationFilter?, description: String = "Serialization failure"): Element {
val element = bean.serialize(filter)
val element = bean.serialize<Any>(filter)
var actual = JDOMUtil.writeElement(element, "\n").trim()
if (!expected.startsWith(XML_PREFIX) && actual.startsWith(XML_PREFIX)) {
actual = actual.substring(XML_PREFIX.length).trim()
@@ -0,0 +1,61 @@
package com.intellij.configurationStore.xml;
import com.intellij.configurationStore.XmlSerializer;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.xmlb.SerializationFilter;
import com.intellij.util.xmlb.annotations.Transient;
import junit.framework.TestCase;
import org.jdom.Element;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings({"deprecation"})
public class XmlSerializerWithDefaultJDOMExternalizerCompatibilityTest extends TestCase {
public void testCompatibility() throws Exception {
final MyBean bean = new MyBean();
assertCompatibleSerialization(bean, "MyBean");
}
private static void assertCompatibleSerialization(final Object data, final String rootTagName) throws Exception {
assertEquals(serializeWithJDom(data, rootTagName), serializeWithXmlSerializer(data));
}
private static String serializeWithXmlSerializer(final Object data) throws Exception {
Element element = serialize(data, null);
String s = JDOMUtil.writeElement(element, "\n");
return StringUtil.trimStart(s, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>").trim();
}
private static String serializeWithJDom(final Object data, String rootTagName) throws Exception {
final Element jDomRoot = new Element(rootTagName);
if (data instanceof com.intellij.openapi.util.JDOMExternalizable) {
((com.intellij.openapi.util.JDOMExternalizable)data).writeExternal(jDomRoot);
}
else {
com.intellij.openapi.util.DefaultJDOMExternalizer.writeExternal(data, jDomRoot);
}
return JDOMUtil.writeElement(jDomRoot, "\n").trim();
}
private static Element serialize(Object bean, @Nullable SerializationFilter filter) {
return XmlSerializer.serialize(bean, filter);
}
@SuppressWarnings("unused")
private static class MyBean {
public int intField = 0;
public int intField2 = 1;
public boolean booleanField = false;
public boolean booleanField2 = true;
public String stringField;
public String stringField2 = "a";
public float floatField;
public float floatField2 = 1;
public transient int transientField;
@Transient
public int transientField2;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi;
import org.jetbrains.annotations.Nullable;
@@ -22,6 +21,5 @@ import org.jetbrains.annotations.Nullable;
* @author yole
*/
public interface PsiNameIdentifierOwner extends PsiNamedElement {
@Nullable
PsiElement getNameIdentifier();
}
@Nullable PsiElement getNameIdentifier();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -16,14 +16,13 @@
package com.intellij.psi;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A PSI element which has a name and can be renamed (for example, a class or a method).
*/
public interface PsiNamedElement extends PsiElement{
public interface PsiNamedElement extends PsiElement {
/**
* The empty array of PSI named elements which can be reused to avoid unnecessary allocations.
*/
@@ -34,7 +33,7 @@ public interface PsiNamedElement extends PsiElement{
*
* @return the element name.
*/
@Nullable @NonNls String getName();
@Nullable String getName();
/**
* Renames the element.
@@ -44,5 +43,5 @@ public interface PsiNamedElement extends PsiElement{
* or a different element if the rename caused the element to be replaced).
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException;
}
PsiElement setName(@NotNull String name) throws IncorrectOperationException;
}
@@ -17,6 +17,7 @@
package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.WalkingState;
import org.jetbrains.annotations.NotNull;
@@ -30,12 +31,17 @@ public abstract class PsiWalkingState extends WalkingState<PsiElement> {
private static class PsiTreeGuide implements TreeGuide<PsiElement> {
@Override
public PsiElement getNextSibling(@NotNull PsiElement element) {
return element.getNextSibling();
return checkSanity(element, element.getNextSibling());
}
private static PsiElement checkSanity(PsiElement element, PsiElement sibling) {
if (sibling == PsiUtilCore.NULL_PSI_ELEMENT) throw new PsiInvalidElementAccessException(element, "Sibling of "+element+" is NULL_PSI_ELEMENT");
return sibling;
}
@Override
public PsiElement getPrevSibling(@NotNull PsiElement element) {
return element.getPrevSibling();
return checkSanity(element, element.getPrevSibling());
}
@Override
@@ -192,7 +192,9 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
checkMax(false);
if (!affected.isEmpty()) {
for (IntervalNode<T> node : affected) {
// reverse direction to visit leaves first - it's cheaper to compute maxEndOf for them first
for (int i = affected.size() - 1; i >= 0; i--) {
IntervalNode<T> node = affected.get(i);
// assumption: interval.getEndOffset() will never be accessed during remove()
int startOffset = node.intervalStart();
int endOffset = node.intervalEnd();
@@ -15,7 +15,6 @@
*/
package com.intellij.openapi.roots.impl;
import com.intellij.openapi.util.LowMemoryWatcher;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.VolatileNotNullLazyValue;
import com.intellij.openapi.util.registry.Registry;
@@ -35,18 +34,15 @@ public class PackageDirectoryCache {
private final MultiMap<String, VirtualFile> myRootsByPackagePrefix;
private final Map<String, PackageInfo> myDirectoriesByPackageNameCache = ContainerUtil.newConcurrentMap();
private final Set<String> myNonExistentPackages = ContainerUtil.newConcurrentSet();
@SuppressWarnings("UnusedDeclaration")
private final LowMemoryWatcher myLowMemoryWatcher = LowMemoryWatcher.register(new Runnable() {
@Override
public void run() {
myNonExistentPackages.clear();
}
});
public PackageDirectoryCache(MultiMap<String, VirtualFile> rootsByPackagePrefix) {
public PackageDirectoryCache(@NotNull MultiMap<String, VirtualFile> rootsByPackagePrefix) {
myRootsByPackagePrefix = rootsByPackagePrefix;
}
public void onLowMemory() {
myNonExistentPackages.clear();
}
@NotNull
public List<VirtualFile> getDirectoriesByPackageName(@NotNull final String packageName) {
PackageInfo info = getPackageInfo(packageName);
@@ -120,8 +116,8 @@ public class PackageDirectoryCache {
};
PackageInfo(String qname, List<VirtualFile> packageDirectories) {
this.myQname = qname;
this.myPackageDirectories = packageDirectories;
myQname = qname;
myPackageDirectories = packageDirectories;
}
@NotNull
@@ -1,6 +1,6 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -53,7 +53,7 @@ public abstract class CachedValueBase<T> {
@Nullable
private synchronized Data<T> cacheOrGetData(@Nullable Data<T> expected, @Nullable Data<T> updatedValue) {
if (expected != getData()) return null;
if (expected != getRawData()) return null;
if (updatedValue != null) {
myData = new SoftReference<Data<T>>(updatedValue);
@@ -67,7 +67,7 @@ public abstract class CachedValueBase<T> {
}
private synchronized boolean compareAndClearData(Data<T> expected) {
if (getData() == expected) {
if (getRawData() == expected) {
myData = null;
return true;
}
@@ -101,7 +101,7 @@ public abstract class CachedValueBase<T> {
@Nullable
private Data<T> getUpToDateOrNull(boolean dispose) {
final Data<T> data = getData();
final Data<T> data = getRawData();
if (data != null) {
if (isUpToDate(data)) {
@@ -115,7 +115,7 @@ public abstract class CachedValueBase<T> {
}
@Nullable
private Data<T> getData() {
final Data<T> getRawData() {
return SoftReference.dereference(myData);
}
@@ -223,7 +223,7 @@ public abstract class CachedValueBase<T> {
if (stamp.mayCacheNow()) {
while (true) {
Data<T> alreadyComputed = getData();
Data<T> alreadyComputed = getRawData();
boolean reuse = alreadyComputed != null && isUpToDate(alreadyComputed);
Data<T> toReturn = cacheOrGetData(alreadyComputed, reuse ? null : data);
if (toReturn != null) {
@@ -86,7 +86,11 @@ public class CachedValuesManagerImpl extends CachedValuesManager {
private boolean isOutdated(CachedValue<?> value) {
return value instanceof CachedValueBase &&
(!((CachedValueBase)value).isFromMyProject(myProject) || !value.hasUpToDateValue());
(!((CachedValueBase)value).isFromMyProject(myProject) || hasOutdatedValue((CachedValueBase)value));
}
private static boolean hasOutdatedValue(CachedValueBase base) {
return !base.hasUpToDateValue() && base.getRawData() != null;
}
public Project getProject() {
@@ -15,6 +15,7 @@
*/
package com.intellij.util;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.LowMemoryWatcher;
import com.intellij.util.containers.WeakList;
import org.jetbrains.annotations.NotNull;
@@ -34,15 +35,20 @@ public class SofterReference<T> {
private volatile Reference<T> myRef;
private static final WeakList<SofterReference> ourRegistry = new WeakList<SofterReference>();
@SuppressWarnings("UnusedDeclaration")
private static final LowMemoryWatcher ourWatcher = LowMemoryWatcher.register(new Runnable() {
@Override
public void run() {
for (SofterReference reference : ourRegistry.copyAndClear()) {
reference.weaken();
}
private static void onLowMemory() {
for (SofterReference reference : ourRegistry.copyAndClear()) {
reference.weaken();
}
});
}
static {
LowMemoryWatcher.register(new Runnable() {
@Override
public void run() {
onLowMemory();
}
}, ApplicationManager.getApplication());
}
public SofterReference(@NotNull T referent) {
ourRegistry.add(this);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -20,7 +20,6 @@ import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
import com.intellij.util.xmlb.XmlSerializer;
import org.jdom.Element;
@@ -65,8 +64,8 @@ public class MultilanguageDuplocatorSettings implements PersistentStateComponent
SkipDefaultValuesSerializationFilters filter = new SkipDefaultValuesSerializationFilters();
for (String name : mySettingsMap.keySet()) {
Element child = XmlSerializer.serialize(mySettingsMap.get(name), filter);
if (!JDOMUtil.isEmpty(child)) {
Element child = XmlSerializer.serializeIfNotDefault(mySettingsMap.get(name), filter);
if (child != null) {
child.setName("object");
child.setAttribute("language", name);
state.addContent(child);
@@ -388,18 +388,21 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
@NotNull private final Project myProject;
@Nullable private final String mySettingName;
private final boolean myDefaultExpandValue;
private boolean myIsExpanded;
@NotNull private final String myToCollapseText;
@NotNull private final String myToExpandText;
public MoreAction(@NotNull Project project, int numberOfHiddenNodes, @Nullable String settingName) {
public MoreAction(@NotNull Project project, int numberOfHiddenNodes, @Nullable String settingName, boolean defaultExpandValue) {
super();
myProject = project;
mySettingName = settingName;
myDefaultExpandValue = defaultExpandValue;
assert numberOfHiddenNodes > 0;
myToExpandText = "Show " + numberOfHiddenNodes + " More...";
myToCollapseText = "Show Only Favorites";
setExpanded(settingName != null && PropertiesComponent.getInstance(project).getBoolean(settingName, false));
setExpanded(
settingName != null ? PropertiesComponent.getInstance(project).getBoolean(settingName, defaultExpandValue) : defaultExpandValue);
}
@Override
@@ -430,7 +433,7 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
public void saveState() {
if (mySettingName != null) {
PropertiesComponent.getInstance(myProject).setValue(mySettingName, myIsExpanded);
PropertiesComponent.getInstance(myProject).setValue(mySettingName, myIsExpanded, myDefaultExpandValue);
}
}
}
@@ -456,8 +459,14 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
public static void wrapWithMoreActionIfNeeded(@NotNull Project project,
@NotNull DefaultActionGroup parentGroup, @NotNull List<? extends ActionGroup> actionList,
int maxIndex, @Nullable String settingName) {
wrapWithMoreActionIfNeeded(project, parentGroup, actionList, maxIndex, settingName, false);
}
public static void wrapWithMoreActionIfNeeded(@NotNull Project project,
@NotNull DefaultActionGroup parentGroup, @NotNull List<? extends ActionGroup> actionList,
int maxIndex, @Nullable String settingName, boolean defaultExpandValue) {
if (actionList.size() > maxIndex) {
MoreAction moreAction = new MoreAction(project, actionList.size() - maxIndex, settingName);
MoreAction moreAction = new MoreAction(project, actionList.size() - maxIndex, settingName, defaultExpandValue);
for (int i = 0; i < actionList.size(); i++) {
parentGroup.add(i < maxIndex ? actionList.get(i) : new HideableActionGroup(actionList.get(i), moreAction));
}
@@ -98,6 +98,18 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
@Transient
var PRESENTATION_MODE = false
@Suppress("unused")
@Deprecated("Use overrideLafFonts", replaceWith = ReplaceWith("overrideLafFonts"))
@JvmField
@Transient
var OVERRIDE_NONIDEA_LAF_FONTS = false
@Suppress("unused")
@Deprecated("Use presentationModeFontSize", replaceWith = ReplaceWith("presentationModeFontSize"))
@JvmField
@Transient
var PRESENTATION_MODE_FONT_SIZE = 24
@get:OptionTag("REUSE_NOT_MODIFIED_TABS") var reuseNotModifiedTabs by storedProperty(false)
@get:OptionTag("ANIMATE_WINDOWS") var animateWindows by storedProperty(true)
@get:OptionTag("SHOW_TOOL_WINDOW_NUMBERS") var showToolWindowsNumbers by storedProperty(true)
@@ -117,36 +129,36 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
@get:OptionTag("HIDE_TABS_IF_NEED") var hideTabsIfNeed by storedProperty(true)
@get:OptionTag("SHOW_CLOSE_BUTTON") var showCloseButton by storedProperty(true)
@get:OptionTag("EDITOR_TAB_PLACEMENT") var editorTabPlacement by storedProperty(1)
@JvmField var HIDE_KNOWN_EXTENSION_IN_TABS = false
@JvmField var SHOW_ICONS_IN_QUICK_NAVIGATION = true
@JvmField var CLOSE_NON_MODIFIED_FILES_FIRST = false
@JvmField var ACTIVATE_MRU_EDITOR_ON_CLOSE = false
@JvmField var ACTIVATE_RIGHT_EDITOR_ON_CLOSE = false
@get:OptionTag("HIDE_KNOWN_EXTENSION_IN_TABS") var hdeKnownExtensionInTabs by storedProperty(false)
@get:OptionTag("SHOW_ICONS_IN_QUICK_NAVIGATION") var showIconInQuickNavigation by storedProperty(true)
@get:OptionTag("CLOSE_NON_MODIFIED_FILES_FIRST") var closeNonModifiedFilesFirst by storedProperty(false)
@get:OptionTag("ACTIVATE_MRU_EDITOR_ON_CLOSE") var activeMruEditorOnClose by storedProperty(false)
@get:OptionTag("ACTIVATE_RIGHT_EDITOR_ON_CLOSE") var activeRigtEditorOnClose by storedProperty(false)
@get:OptionTag("IDE_AA_TYPE") var ideAAType by storedProperty(AntialiasingType.SUBPIXEL)
@get:OptionTag("EDITOR_AA_TYPE") var editorAAType by storedProperty(AntialiasingType.SUBPIXEL)
@JvmField var COLOR_BLINDNESS: ColorBlindness? = null
@JvmField var MOVE_MOUSE_ON_DEFAULT_BUTTON = false
@JvmField var ENABLE_ALPHA_MODE = false
@JvmField var ALPHA_MODE_DELAY = 1500
@JvmField var ALPHA_MODE_RATIO = 0.5f
@JvmField var MAX_CLIPBOARD_CONTENTS = 5
@JvmField var OVERRIDE_NONIDEA_LAF_FONTS = false
@JvmField var SHOW_ICONS_IN_MENUS = true
@JvmField var DISABLE_MNEMONICS = SystemInfo.isMac // IDEADEV-33409, should be disabled by default on MacOS
@JvmField var DISABLE_MNEMONICS_IN_CONTROLS = false
@JvmField var USE_SMALL_LABELS_ON_TABS = SystemInfo.isMac
@JvmField var MAX_LOOKUP_WIDTH2 = 500
@JvmField var MAX_LOOKUP_LIST_HEIGHT = 11
@JvmField var HIDE_NAVIGATION_ON_FOCUS_LOSS = true
@JvmField var DND_WITH_PRESSED_ALT_ONLY = false
@JvmField var DEFAULT_AUTOSCROLL_TO_SOURCE = false
@get:OptionTag("MOVE_MOUSE_ON_DEFAULT_BUTTON") var moveMouseOnDefaultButton by storedProperty(false)
@get:OptionTag("ENABLE_ALPHA_MODE") var enableAlphaMode by storedProperty(false)
@get:OptionTag("ALPHA_MODE_DELAY") var alphaModeDelay by storedProperty(1500)
@get:OptionTag("ALPHA_MODE_RATIO") var alphaModeRatio by storedProperty(0.5f)
@get:OptionTag("MAX_CLIPBOARD_CONTENTS") var maxClipboardContents by storedProperty(5)
@get:OptionTag("OVERRIDE_NONIDEA_LAF_FONTS") var overrideLafFonts by storedProperty(false)
@get:OptionTag("SHOW_ICONS_IN_MENUS") var showIconsInMenus by storedProperty(true)
// IDEADEV-33409, should be disabled by default on MacOS
@get:OptionTag("DISABLE_MNEMONICS") var disableMnemonics by storedProperty(SystemInfo.isMac)
@get:OptionTag("DISABLE_MNEMONICS_IN_CONTROLS") var disableMnemonicsInControls by storedProperty(false)
@get:OptionTag("USE_SMALL_LABELS_ON_TABS") var useSmallLabelsOnTabs by storedProperty(SystemInfo.isMac)
@get:OptionTag("MAX_LOOKUP_WIDTH2") var maxLookupWidth by storedProperty(500)
@get:OptionTag("MAX_LOOKUP_LIST_HEIGHT") var maxLookupListHeight by storedProperty(11)
@get:OptionTag("HIDE_NAVIGATION_ON_FOCUS_LOSS") var hideNavigationOnFocusLoss by storedProperty(true)
@get:OptionTag("DND_WITH_PRESSED_ALT_ONLY") var dndWithPressedAltOnly by storedProperty(false)
@get:OptionTag("DEFAULT_AUTOSCROLL_TO_SOURCE") var defaultAutoScrollToSource by storedProperty(false)
@Transient var presentationMode = false
@JvmField var PRESENTATION_MODE_FONT_SIZE = 24
@JvmField var MARK_MODIFIED_TABS_WITH_ASTERISK = false
@JvmField var SHOW_TABS_TOOLTIPS = true
@JvmField var SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true
@JvmField var NAVIGATE_TO_PREVIEW = false
@get:OptionTag("PRESENTATION_MODE_FONT_SIZE") var presentationModeFontSize by storedProperty(24)
@get:OptionTag("MARK_MODIFIED_TABS_WITH_ASTERISK") var markModifiedTabsWithAsterisk by storedProperty(false)
@get:OptionTag("SHOW_TABS_TOOLTIPS") var showTabsTooltips by storedProperty(true)
@get:OptionTag("SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES") var showDirectoryForNonUniqueFilenames by storedProperty(true)
@get:OptionTag("NAVIGATE_TO_PREVIEW") var navigateToPreview by storedProperty(false)
private val myTreeDispatcher = ComponentTreeEventDispatcher.create(UISettingsListener::class.java)
@@ -162,9 +174,8 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
init {
tweakPlatformDefaults()
val scrollToSource = WelcomeWizardUtil.getAutoScrollToSource()
if (scrollToSource != null) {
DEFAULT_AUTOSCROLL_TO_SOURCE = scrollToSource
WelcomeWizardUtil.getAutoScrollToSource()?.let {
defaultAutoScrollToSource = it
}
}
@@ -177,8 +188,8 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
// TODO[anton] consider making all IDEs use the same settings
if (PlatformUtils.isAppCode()) {
scrollTabLayoutInEditor = true
ACTIVATE_RIGHT_EDITOR_ON_CLOSE = true
SHOW_ICONS_IN_MENUS = false
activeRigtEditorOnClose = true
showIconsInMenus = false
}
}
@@ -215,6 +226,8 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
SHOW_CLOSE_BUTTON = showCloseButton
EDITOR_AA_TYPE = editorAAType
PRESENTATION_MODE = presentationMode
OVERRIDE_NONIDEA_LAF_FONTS = overrideLafFonts
PRESENTATION_MODE_FONT_SIZE = presentationModeFontSize
}
private fun initDefFont() {
@@ -253,11 +266,11 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
}
// Check that alpha delay and ratio are valid
if (ALPHA_MODE_DELAY < 0) {
ALPHA_MODE_DELAY = 1500
if (alphaModeDelay < 0) {
alphaModeDelay = 1500
}
if (ALPHA_MODE_RATIO < 0.0f || ALPHA_MODE_RATIO > 1.0f) {
ALPHA_MODE_RATIO = 0.5f
if (alphaModeRatio < 0.0f || alphaModeRatio > 1.0f) {
alphaModeRatio = 0.5f
}
if (FONT_SCALE <= 0) {
@@ -292,8 +305,8 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
}
}
if (MAX_CLIPBOARD_CONTENTS <= 0) {
MAX_CLIPBOARD_CONTENTS = 5
if (maxClipboardContents <= 0) {
maxClipboardContents = 5
}
fireUISettingsChanged()
@@ -80,14 +80,14 @@ public abstract class AnAction implements PossiblyDumbAware {
/**
* Creates a new action with its text, description and icon set to <code>null</code>.
* Creates a new action with its text, description and icon set to {@code null}.
*/
public AnAction(){
this(null, null, null);
}
/**
* Creates a new action with <code>icon</code> provided. Its text, description set to <code>null</code>.
* Creates a new action with {@code icon} provided. Its text, description set to {@code null}.
*
* @param icon Default icon to appear in toolbars and menus (Note some platform don't have icons in menu).
*/
@@ -97,7 +97,7 @@ public abstract class AnAction implements PossiblyDumbAware {
/**
* Creates a new action with the specified text. Description and icon are
* set to <code>null</code>.
* set to {@code null}.
*
* @param text Serves as a tooltip when the presentation is a button and the name of the
* menu item when the presentation is a menu item.
@@ -167,12 +167,7 @@ public abstract class AnAction implements PossiblyDumbAware {
}
if (parentDisposable != null) {
Disposer.register(parentDisposable, new Disposable() {
@Override
public void dispose() {
unregisterCustomShortcutSet(component);
}
});
Disposer.register(parentDisposable, () -> unregisterCustomShortcutSet(component));
}
}
@@ -184,9 +179,9 @@ public abstract class AnAction implements PossiblyDumbAware {
}
/**
* Copies template presentation and shortcuts set from <code>sourceAction</code>.
* Copies template presentation and shortcuts set from {@code sourceAction}.
*
* @param sourceAction cannot be <code>null</code>
* @param sourceAction cannot be {@code null}
*/
public final void copyFrom(@NotNull AnAction sourceAction){
Presentation sourcePresentation = sourceAction.getTemplatePresentation();
@@ -15,7 +15,6 @@
*/
package com.intellij.openapi.actionSystem;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -32,7 +31,7 @@ public final class CustomShortcutSet implements ShortcutSet {
private final Shortcut[] myShortcuts;
/**
* Creates <code>CustomShortcutSet</code> which contains only one
* Creates {@code CustomShortcutSet} which contains only one
* single stroke keyboard shortcut.
*/
public CustomShortcutSet(@NotNull KeyStroke keyStroke){
@@ -40,7 +39,7 @@ public final class CustomShortcutSet implements ShortcutSet {
}
/**
* Creates <code>CustomShortcutSet</code> which contains specified keyboard and
* Creates {@code CustomShortcutSet} which contains specified keyboard and
* mouse shortcuts.
*
* @param shortcuts keyboard shortcuts
@@ -49,7 +48,7 @@ public final class CustomShortcutSet implements ShortcutSet {
myShortcuts = shortcuts.length == 0 ? Shortcut.EMPTY_ARRAY : shortcuts.clone();
}
public CustomShortcutSet(Integer... keyCodes) {
public CustomShortcutSet(@NotNull Integer... keyCodes) {
myShortcuts = ContainerUtil.map(keyCodes, integer -> new KeyboardShortcut(KeyStroke.getKeyStroke(integer, 0), null), Shortcut.EMPTY_ARRAY);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -137,7 +137,7 @@ public final class Presentation implements Cloneable {
if (i >= text.length()) break;
ch = text.charAt(i);
if (ch != '_' && ch != '&') {
if (UISettings.getInstance().DISABLE_MNEMONICS_IN_CONTROLS) {
if (UISettings.getInstance().getDisableMnemonicsInControls()) {
myMnemonic = 0;
myDisplayedMnemonicIndex = -1;
}
@@ -219,9 +219,10 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
@Override
public Font getFont(EditorFontType key) {
if (UISettings.getInstance().getPresentationMode()) {
UISettings uiSettings = UISettings.getInstance();
if (uiSettings.getPresentationMode()) {
final Font font = myFonts.get(key);
return new Font(font.getName(), font.getStyle(), UISettings.getInstance().PRESENTATION_MODE_FONT_SIZE);
return new Font(font.getName(), font.getStyle(), uiSettings.getPresentationModeFontSize());
}
return myFonts.get(key);
}
@@ -23,12 +23,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
/**
* Action for grouping items in a runtime dashboard tree.
* Action for grouping items in a run dashboard tree.
*
* @author konstantin.aleev
*/
public interface DashboardGroupingRule extends TreeAction {
ExtensionPointName<DashboardGroupingRule> EP_NAME = ExtensionPointName.create("com.intellij.runtimeDashboardGroupingRule");
ExtensionPointName<DashboardGroupingRule> EP_NAME = ExtensionPointName.create("com.intellij.runDashboardGroupingRule");
Comparator<DashboardGroupingRule> PRIORITY_COMPARATOR = (o1, o2) -> {
final int res = o2.getPriority() - o1.getPriority();
@@ -25,11 +25,11 @@ import javax.swing.*;
*/
public class DashboardRunConfigurationStatus {
public static final DashboardRunConfigurationStatus STARTED = new DashboardRunConfigurationStatus(
ExecutionBundle.message("runtime.dashboard.started.group.name"), AllIcons.Toolwindows.ToolWindowRun);
ExecutionBundle.message("run.dashboard.started.group.name"), AllIcons.Toolwindows.ToolWindowRun);
public static final DashboardRunConfigurationStatus STOPPED = new DashboardRunConfigurationStatus(
ExecutionBundle.message("runtime.dashboard.stopped.group.name"), AllIcons.Actions.Suspend);
ExecutionBundle.message("run.dashboard.stopped.group.name"), AllIcons.Actions.Suspend);
public static final DashboardRunConfigurationStatus FAILED = new DashboardRunConfigurationStatus(
ExecutionBundle.message("runtime.dashboard.failed.group.name"), AllIcons.General.Error);
ExecutionBundle.message("run.dashboard.failed.group.name"), AllIcons.General.Error);
private final String myName;
private final Icon myIcon;
@@ -24,18 +24,18 @@ import com.intellij.openapi.util.registry.Registry;
import org.jetbrains.annotations.ApiStatus;
/**
* In order to show run configurations of the specific configuration type in Runtime Dashboard tool window,
* In order to show run configurations of the specific configuration type in Run Dashboard tool window,
* one should register this extension.
*
* @author konstantin.aleev
*/
@ApiStatus.Experimental
public abstract class RuntimeDashboardContributor {
public static final ExtensionPointName<RuntimeDashboardContributor> EP_NAME = ExtensionPointName.create("com.intellij.runtimeDashboardContributor");
public abstract class RunDashboardContributor {
public static final ExtensionPointName<RunDashboardContributor> EP_NAME = ExtensionPointName.create("com.intellij.runDashboardContributor");
private final ConfigurationType myType;
protected RuntimeDashboardContributor(ConfigurationType type) {
protected RunDashboardContributor(ConfigurationType type) {
myType = type;
}
@@ -74,13 +74,13 @@ public abstract class RuntimeDashboardContributor {
return DashboardRunConfigurationStatus.FAILED;
}
public static RuntimeDashboardContributor getContributor(ConfigurationType type) {
if (!Registry.is("ide.runtime.dashboard")) {
public static RunDashboardContributor getContributor(ConfigurationType type) {
if (!Registry.is("ide.run.dashboard")) {
return null;
}
if (type != null) {
for (RuntimeDashboardContributor contributor : EP_NAME.getExtensions()) {
for (RunDashboardContributor contributor : EP_NAME.getExtensions()) {
if (type.equals(contributor.getType())) {
return contributor;
}
@@ -25,12 +25,12 @@ import javax.swing.*;
/**
* @author konstantin.aleev
*/
public interface RuntimeDashboardManager {
public interface RunDashboardManager {
Topic<DashboardListener> DASHBOARD_TOPIC =
Topic.create("runtime dashboard", DashboardListener.class, Topic.BroadcastDirection.TO_PARENT);
Topic.create("run dashboard", DashboardListener.class, Topic.BroadcastDirection.TO_PARENT);
static RuntimeDashboardManager getInstance(Project project) {
return ServiceManager.getService(project, RuntimeDashboardManager.class);
static RunDashboardManager getInstance(Project project) {
return ServiceManager.getService(project, RunDashboardManager.class);
}
ContentManager getDashboardContentManager();
@@ -71,7 +71,7 @@
</constraints>
<properties/>
</component>
<component id="51007" class="javax.swing.JLabel">
<component id="51007" class="javax.swing.JLabel" binding="myAutoInsertLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
@@ -156,9 +156,6 @@
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<clientProperties>
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
</clientProperties>
<border type="none" title-resource-bundle="messages/ApplicationBundle" title-key="title.parameter.info"/>
<children>
<component id="c7fb5" class="javax.swing.JCheckBox" binding="myCbParameterInfoPopup">
@@ -43,6 +43,7 @@ public class CodeCompletionPanel {
private JCheckBox myCbAutopopupJavaDoc;
private JTextField myAutopopupJavaDocField;
private JLabel myAutoInsertLabel;
private JCheckBox myCbOnCodeCompletion;
private JCheckBox myCbOnSmartTypeCompletion;
@@ -101,6 +102,9 @@ public class CodeCompletionPanel {
);
hideOption(myCbOnSmartTypeCompletion, OptionId.COMPLETION_SMART_TYPE);
hideOption(myCbOnCodeCompletion, OptionId.AUTOCOMPLETE_ON_BASIC_CODE_COMPLETION);
if(!myCbOnSmartTypeCompletion.isVisible() && !myCbOnCodeCompletion.isVisible())
myAutoInsertLabel.setVisible(false);
reset();
}

Some files were not shown because too many files have changed in this diff Show More