Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2013-12-23 15:32:01 +04:00
580 changed files with 9039 additions and 2241 deletions
+2 -2
View File
@@ -1,11 +1,11 @@
<component name="libraryTable">
<library name="commons-logging">
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/commons-logging-1.1.1.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/commons-logging-1.1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$PROJECT_DIR$/lib/src/commons-logging-1.1.1-src.zip!/commons-logging-1.1.1-src/src/java" />
<root url="jar://$PROJECT_DIR$/lib/src/commons-logging-1.1.3-src.zip!/commons-logging-1.1.3-src/src/main/java" />
</SOURCES>
</library>
</component>
+1 -1
View File
@@ -1,7 +1,7 @@
<component name="libraryTable">
<library name="http-client-3.1">
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/commons-logging-1.1.1.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/commons-logging-1.1.3.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/commons-httpclient-3.1-patched.jar!/" />
</CLASSES>
<JAVADOC>
+1
View File
@@ -196,6 +196,7 @@ libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as licens
libraryLicense(name: "JCIP Annotations", libraryName: "jcip", license: "Creative Commons Attribution License", url: "http://www.jcip.net", licenseUrl: "http://creativecommons.org/licenses/by/2.5")
libraryLicense(name: "JDOM", version: "1.1 (with patches by JetBrains)", license: "modified Apache", url: "http://www.jdom.org/", licenseUrl: "http://www.jdom.org/docs/faq.html#a0030")
libraryLicense(name: "jgit-2.1.0", version: "2.1.0.201209190230", license: "EDL/BSD", url: "http://www.eclipse.org/jgit/", licenseUrl: "http://www.eclipse.org/org/documents/edl-v10.php", attachedTo: "git4idea")
libraryLicense(name: "javawriter", libraryName: "javawriter", license: "Apache 2.0", url: "https://github.com/square/javawriter")
libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "1.1-preview 2006-05-04 11:55:37", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
+39 -4
View File
@@ -1363,11 +1363,46 @@
<option name="ERROR_STRIPE_COLOR" value="246e00" />
</value>
</option>
<option name="STATIC_FIELD_ATTRIBUTES">
<option name="SEARCH_RESULT_ATTRIBUTES">
<value>
<option name="FOREGROUND" value="9876aa" />
<option name="FONT_TYPE" value="2" />
<option name="EFFECT_TYPE" value="1" />
<option name="BACKGROUND" value="155221" />
<option name="ERROR_STRIPE_COLOR" value="246e00" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="STATIC_FINAL_FIELD_ATTRIBUTES">
@@ -1122,6 +1122,42 @@
<option name="BACKGROUND" value="ffa600" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="SQL_COLUMN">
<value>
<option name="FOREGROUND" value="cc9900" />
@@ -1912,6 +1912,42 @@
<option name="FOREGROUND" value="66CC33" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="SQL_BAD_CHARACTER">
<value>
<option name="BACKGROUND" value="6e3b3b" />
@@ -1306,6 +1306,42 @@
<option name="FOREGROUND" value="FF6400" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="STATIC_FIELD_ATTRIBUTES">
<value>
<option name="FOREGROUND" value="fda5ff" />
+36
View File
@@ -1812,6 +1812,42 @@
<option name="FOREGROUND" value="E1EFFF" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="STATIC_FIELD_ATTRIBUTES">
<value>
<option name="FOREGROUND" value="fda5ff" />
+36
View File
@@ -1395,6 +1395,42 @@
<option name="FOREGROUND" value="A6E22E" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="STATIC_FIELD_ATTRIBUTES">
<value>
<option name="FOREGROUND" value="fda5ff" />
@@ -1492,6 +1492,42 @@
<option name="FOREGROUND" value="E8BF6A" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="STATIC_FIELD_ATTRIBUTES">
<value>
<option name="FOREGROUND" value="fda5ff" />
@@ -1543,6 +1543,42 @@
<option name="FOREGROUND" value="9B703F" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="STATIC_FIELD_ATTRIBUTES">
<value>
<option name="FOREGROUND" value="fda5ff" />
@@ -1817,6 +1817,42 @@
<option name="FOREGROUND" value="66ff00" />
</value>
</option>
<option name="SPY-JS.FUNCTION_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PROGRAM_SCOPE">
<value>
<option name="BACKGROUND" value="3A3A3A"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.EXCEPTION">
<value>
<option name="BACKGROUND" value="532B2E"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_ONE">
<value>
<option name="BACKGROUND" value="425F44"/>
<option name="EFFECT_TYPE" value="2"/>
</value>
</option>
<option name="SPY-JS.PATH_LEVEL_TWO">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="1"/>
</value>
</option>
<option name="SPY-JS.VALUE_HINT">
<value>
<option name="EFFECT_COLOR" value="a9b7c6" />
<option name="EFFECT_TYPE" value="0"/>
</value>
</option>
<option name="SQL_BAD_CHARACTER">
<value>
<option name="BACKGROUND" value="6e3b3b" />
@@ -46,7 +46,13 @@ public class ChunkBuild extends CompositeGenerator{
}
}
add(new Property(BuildProperties.getModuleChunkCompilerArgsProperty(chunk.getName()), BuildProperties.propertyRef(BuildProperties.PROPERTY_COMPILER_ADDITIONAL_ARGS)), 1);
final StringBuilder compileArgs = new StringBuilder();
compileArgs.append(chunk.getChunkSpecificCompileOptions());
if (compileArgs.length() > 0) {
compileArgs.append(" ");
}
compileArgs.append(BuildProperties.propertyRef(BuildProperties.PROPERTY_COMPILER_ADDITIONAL_ARGS));
add(new Property(BuildProperties.getModuleChunkCompilerArgsProperty(chunk.getName()), compileArgs.toString()), 1);
final String outputPathUrl = chunk.getOutputDirUrl();
String location = outputPathUrl != null?
@@ -19,7 +19,7 @@ import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.ex.CompileContextEx;
import com.intellij.openapi.module.LanguageLevelUtil;
import com.intellij.openapi.module.EffectiveLanguageLevelUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
@@ -304,7 +304,7 @@ public class ModuleChunk extends Chunk<Module> {
//the check for equal language levels is done elsewhere
public LanguageLevel getLanguageLevel() {
return LanguageLevelUtil.getEffectiveLanguageLevel(getNodes().iterator().next());
return EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(getNodes().iterator().next());
}
public Project getProject() {
@@ -15,14 +15,21 @@
*/
package com.intellij.compiler.ant;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerEncodingService;
import com.intellij.openapi.module.EffectiveLanguageLevelUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.CompilerModuleExtension;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Comparator;
@@ -123,6 +130,18 @@ public class ModuleChunk {
return myMainModule.getProject();
}
public String getChunkSpecificCompileOptions() {
final StringBuilder options = new StringBuilder();
final Charset encoding = CompilerEncodingService.getInstance(getProject()).getPreferredModuleEncoding(myMainModule);
if (encoding != null) {
appendOption(options, "-encoding", encoding.name());
}
appendOption(options, "-source", getLanguageLevelOption(EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(myMainModule)));
appendOption(options, "-target", CompilerConfiguration.getInstance(getProject()).getBytecodeTargetLevel(myMainModule));
return options.toString();
}
public boolean contains(final Module module) {
for (Module chunkModule : myModules) {
if (chunkModule.equals(module)) {
@@ -131,4 +150,28 @@ public class ModuleChunk {
}
return false;
}
private static void appendOption(StringBuilder options, @NotNull final String name, @Nullable String value) {
if (!StringUtil.isEmpty(value)) {
if (options.length() > 0) {
options.append(" ");
}
options.append(name).append(" ").append(value);
}
}
private static String getLanguageLevelOption(LanguageLevel level) {
if (level != null) {
switch (level) {
case JDK_1_3: return "1.3";
case JDK_1_4: return "1.4";
case JDK_1_5: return "1.5";
case JDK_1_6: return "1.6";
case JDK_1_7: return "1.7";
case JDK_1_8: return "8";
}
}
return null;
}
}
@@ -229,6 +229,8 @@ public class DebuggerExpressionComboBox extends DebuggerEditorImpl {
final EditorTextField textField = (EditorTextField)editorComponent;
final Editor editor = textField.getEditor();
if (editor != null) {
int textLength = editor.getDocument().getTextLength();
offset = Math.min(offset, textLength);
textField.getCaretModel().moveToOffset(offset);
editor.getSelectionModel().setSelection(offset, offset);
}
@@ -136,19 +136,18 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable {
MultiMap<TemplatesGroup,ProjectTemplate> templatesMap = CreateFromTemplateMode.getTemplatesMap(context, false);
List<TemplatesGroup> groups = new ArrayList<TemplatesGroup>(templatesMap.keySet());
Collections.sort(groups);
MultiMap<String, ProjectCategory> map = new MultiMap<String, ProjectCategory>();
MultiMap<TemplatesGroup, ProjectCategory> map = new MultiMap<TemplatesGroup, ProjectCategory>();
for (TemplatesGroup group : groups) {
String name = group.getName();
for (ProjectTemplate template : templatesMap.get(group)) {
TemplateBasedProjectType projectType = new TemplateBasedProjectType(template);
map.putValue(name, projectType);
map.putValue(group, projectType);
}
for (ProjectCategory category : categories.get(name)) {
map.putValue(name, category);
for (ProjectCategory category : categories.get(group.getName())) {
map.putValue(group, category);
}
}
myProjectTypesList = new ProjectTypesList(myProjectTypeList, map);
myProjectTypesList = new ProjectTypesList(myProjectTypeList, map, myBuilders);
myProjectTypeList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
@@ -16,26 +16,30 @@
package com.intellij.ide.projectWizard;
import com.intellij.ide.util.newProjectWizard.SelectTemplateSettings;
import com.intellij.ide.util.newProjectWizard.TemplatesGroup;
import com.intellij.ide.util.projectWizard.ModuleBuilder;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.ui.popup.ListItemDescriptor;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.platform.ProjectTemplatesFactory;
import com.intellij.ui.CollectionListModel;
import com.intellij.ui.ListSpeedSearch;
import com.intellij.ui.SpeedSearchComparator;
import com.intellij.ui.components.JBList;
import com.intellij.ui.popup.list.GroupedItemsListRenderer;
import com.intellij.util.containers.FactoryMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
/**
* @author Dmitry Avdeev
@@ -47,7 +51,7 @@ public class ProjectTypesList implements Disposable {
private final CollectionListModel<TemplateItem> myModel;
private Pair<TemplateItem, Integer> myBestMatch;
public ProjectTypesList(JBList list, MultiMap<String, ProjectCategory> map) {
public ProjectTypesList(JBList list, MultiMap<TemplatesGroup, ProjectCategory> map, FactoryMap<ProjectCategory, ModuleBuilder> builders) {
myList = list;
myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -58,7 +62,7 @@ public class ProjectTypesList implements Disposable {
return super.getElementText(element);
}
}.setComparator(new SpeedSearchComparator(false));
List<TemplateItem> items = buildItems(map);
List<TemplateItem> items = buildItems(map, builders);
myModel = new CollectionListModel<TemplateItem>(items);
myList.setCellRenderer(new GroupedItemsListRenderer(new ListItemDescriptor() {
@@ -137,19 +141,50 @@ public class ProjectTypesList implements Disposable {
}
}
private List<TemplateItem> buildItems(MultiMap<String, ProjectCategory> map) {
private static List<TemplateItem> buildItems(final MultiMap<TemplatesGroup, ProjectCategory> map, final FactoryMap<ProjectCategory, ModuleBuilder> builders) {
List<TemplateItem> items = new ArrayList<TemplateItem>();
List<String> groups = new ArrayList<String>(map.keySet());
Collections.sort(groups);
for (String group : groups) {
List<TemplatesGroup> groups = new ArrayList<TemplatesGroup>(map.keySet());
final Map<ModuleType, Integer> moduleTypeMap = new HashMap<ModuleType, Integer>();
for (ProjectCategory category : map.values()) {
ModuleType type = builders.get(category).getModuleType();
Integer integer = moduleTypeMap.get(type);
moduleTypeMap.put(type, integer == null ? 0 : integer + 1);
}
Collections.sort(groups, new Comparator<TemplatesGroup>() {
@Override
public int compare(TemplatesGroup o1, TemplatesGroup o2) {
int weight = Comparing.compare(o1.getName().equals(ProjectTemplatesFactory.OTHER_GROUP), o2.getName().equals(ProjectTemplatesFactory.OTHER_GROUP));
if (weight != 0) return weight;
int byModuleType = getModuleTypePopularity(o2, map, builders, moduleTypeMap) - getModuleTypePopularity(o1, map, builders, moduleTypeMap);
if (byModuleType != 0) return byModuleType;
int i = map.get(o2).size() - map.get(o1).size(); // compare group size
return i == 0 ? o1.compareTo(o2) : i;
}
});
for (TemplatesGroup group : groups) {
for (ProjectCategory template : map.get(group)) {
TemplateItem templateItem = new TemplateItem(template, group);
TemplateItem templateItem = new TemplateItem(template, group.getName());
items.add(templateItem);
}
}
return items;
}
private static int getModuleTypePopularity(TemplatesGroup group,
MultiMap<TemplatesGroup, ProjectCategory> map,
FactoryMap<ProjectCategory, ModuleBuilder> builders,
Map<ModuleType, Integer> moduleTypeMap) {
int moduleTypePopularity = 0;
for (ProjectCategory category : map.get(group)) {
ModuleType type = builders.get(category).getModuleType();
moduleTypePopularity = Math.max(moduleTypePopularity, moduleTypeMap.get(type));
}
return moduleTypePopularity;
}
@Nullable
public ProjectCategory getSelectedType() {
Object value = myList.getSelectedValue();
@@ -53,6 +53,10 @@ public class AddAssertStatementFix implements LocalQuickFix {
PsiElement element = descriptor.getPsiElement();
PsiElement anchorElement = PsiTreeUtil.getParentOfType(element, PsiStatement.class);
LOG.assertTrue(anchorElement != null);
final PsiElement tempParent = anchorElement.getParent();
if (tempParent instanceof PsiForStatement && !PsiTreeUtil.isAncestor(((PsiForStatement)tempParent).getBody(), anchorElement, false)) {
anchorElement = tempParent;
}
PsiElement prev = PsiTreeUtil.skipSiblingsBackward(anchorElement, PsiWhiteSpace.class);
if (prev instanceof PsiComment && JavaSuppressionUtil.getSuppressedInspectionIdsIn(prev) != null) {
anchorElement = prev;
@@ -51,11 +51,7 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx {
((RefClassImpl)refClass).setFlag(false, CAN_BE_FINAL_MASK);
return;
}
if (refClass.isAbstract() || refClass.isAnonymous() || refClass.isInterface()) {
((RefClassImpl)refClass).setFlag(false, CAN_BE_FINAL_MASK);
return;
}
if (!refClass.isSelfInheritor(psiClass)) {
if (psiClass != null && !refClass.isSelfInheritor(psiClass)) {
for (PsiClass psiSuperClass : psiClass.getSupers()) {
if (myManager.belongsToScope(psiSuperClass)) {
RefClass refSuperClass = (RefClass)myManager.getReference(psiSuperClass);
@@ -65,6 +61,9 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx {
}
}
}
if (refClass.isAbstract() || refClass.isAnonymous() || refClass.isInterface()) {
((RefClassImpl)refClass).setFlag(false, CAN_BE_FINAL_MASK);
}
}
else if (refElement instanceof RefMethod) {
final RefMethod refMethod = (RefMethod)refElement;
@@ -153,54 +153,55 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
return;
}
lExpr.accept(this);
IElementType op = expression.getOperationTokenType();
PsiType type = expression.getType();
boolean isBoolean = PsiType.BOOLEAN.equals(type);
if (op == JavaTokenType.EQ) {
lExpr.accept(this);
rExpr.accept(this);
generateBoxingUnboxingInstructionFor(rExpr, type);
}
else if (op == JavaTokenType.ANDEQ) {
if (isBoolean) {
generateNonLazyExpression(true, lExpr, rExpr, type);
generateBooleanAssignmentExpression(true, lExpr, rExpr, type);
}
else {
generateDefaultBinOp(lExpr, rExpr, type);
generateDefaultAssignmentBinOp(lExpr, rExpr, type);
}
}
else if (op == JavaTokenType.OREQ) {
if (isBoolean) {
generateNonLazyExpression(false, lExpr, rExpr, type);
generateBooleanAssignmentExpression(false, lExpr, rExpr, type);
}
else {
generateDefaultBinOp(lExpr, rExpr, type);
generateDefaultAssignmentBinOp(lExpr, rExpr, type);
}
}
else if (op == JavaTokenType.XOREQ) {
if (isBoolean) {
generateXorExpression(expression, new PsiExpression[]{lExpr, rExpr}, type);
generateXorExpression(expression, new PsiExpression[]{lExpr, rExpr}, type, true);
}
else {
generateDefaultBinOp(lExpr, rExpr, type);
generateDefaultAssignmentBinOp(lExpr, rExpr, type);
}
}
else if (op == JavaTokenType.PLUSEQ && type != null && type.equalsToText(JAVA_LANG_STRING)) {
lExpr.accept(this);
addInstruction(new DupInstruction());
rExpr.accept(this);
addInstruction(new BinopInstruction(JavaTokenType.PLUS, null, lExpr.getProject()));
}
else {
generateDefaultBinOp(lExpr, rExpr, type);
generateDefaultAssignmentBinOp(lExpr, rExpr, type);
}
addInstruction(new AssignInstruction(rExpr));
finishElement(expression);
}
private void generateDefaultBinOp(PsiExpression lExpr, PsiExpression rExpr, final PsiType exprType) {
private void generateDefaultAssignmentBinOp(PsiExpression lExpr, PsiExpression rExpr, final PsiType exprType) {
lExpr.accept(this);
addInstruction(new DupInstruction());
generateBoxingUnboxingInstructionFor(lExpr,exprType);
rExpr.accept(this);
generateBoxingUnboxingInstructionFor(rExpr, exprType);
@@ -1062,7 +1063,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
generateOrExpression(operands, type, true);
}
else if (op == JavaTokenType.XOR && PsiType.BOOLEAN.equals(type)) {
generateXorExpression(expression, operands, type);
generateXorExpression(expression, operands, type, false);
}
else if (op == JavaTokenType.AND && PsiType.BOOLEAN.equals(type)) {
generateAndExpression(operands, type, false);
@@ -1153,9 +1154,12 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
}
private void generateXorExpression(PsiExpression expression, PsiExpression[] operands, final PsiType exprType) {
private void generateXorExpression(PsiExpression expression, PsiExpression[] operands, final PsiType exprType, boolean forAssignment) {
PsiExpression operand = operands[0];
operand.accept(this);
if (forAssignment) {
addInstruction(new DupInstruction());
}
generateBoxingUnboxingInstructionFor(operand, exprType);
for (int i = 1; i < operands.length; i++) {
operand = operands[i];
@@ -1187,12 +1191,14 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
}
private void generateNonLazyExpression(boolean and, PsiExpression lExpression, PsiExpression rExpression, PsiType exprType) {
rExpression.accept(this);
generateBoxingUnboxingInstructionFor(rExpression, exprType);
private void generateBooleanAssignmentExpression(boolean and, PsiExpression lExpression, PsiExpression rExpression, PsiType exprType) {
lExpression.accept(this);
generateBoxingUnboxingInstructionFor(lExpression, exprType);
addInstruction(new DupInstruction());
rExpression.accept(this);
generateBoxingUnboxingInstructionFor(rExpression, exprType);
addInstruction(new SwapInstruction());
combineStackBooleans(and, lExpression);
}
@@ -1414,14 +1420,14 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
if (contracts.size() > 1) {
addInstruction(new DupInstruction(args.length, contracts.size() - 1));
}
for (MethodContract contract : contracts) {
handleContract(expression, contract);
for (int i = 0; i < contracts.size(); i++) {
handleContract(expression, contracts.get(i), contracts.size() - 1 - i);
}
pushUnknownReturnValue(expression); // goto here if all contracts are false
return true;
}
private void handleContract(PsiMethodCallExpression expression, MethodContract contract) {
private void handleContract(PsiMethodCallExpression expression, MethodContract contract, int remainingContracts) {
PsiExpression[] args = expression.getArgumentList().getExpressions();
final ControlFlow.ControlFlowOffset exitPoint = getEndOffset(expression);
@@ -1448,6 +1454,10 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
continueCheckingContract.setOffset(myCurrentFlow.getInstructionCount());
}
for (int j = 0; j < remainingContracts * args.length; j++) {
addInstruction(new PopInstruction());
}
// if contract is true
switch (contract.returnValue) {
case ANY_VALUE:
@@ -35,8 +35,6 @@ import com.intellij.psi.PsiType;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import gnu.trove.TLongArrayList;
import gnu.trove.TLongHashSet;
import org.jetbrains.annotations.NotNull;
@@ -51,17 +49,17 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
private final List<EqClass> myEqClasses;
private final Stack<DfaValue> myStack;
private final TLongHashSet myDistinctClasses;
private final Map<DfaVariableValue,DfaVariableState> myVariableStates;
private final LinkedHashMap<DfaVariableValue,DfaVariableState> myVariableStates;
private final Map<DfaVariableValue,DfaVariableState> myDefaultVariableStates;
private final Set<DfaVariableValue> myUnknownVariables;
private final LinkedHashSet<DfaVariableValue> myUnknownVariables;
private boolean myEphemeral;
public DfaMemoryStateImpl(final DfaValueFactory factory) {
myFactory = factory;
myDefaultVariableStates = ContainerUtil.newTroveMap();
myEqClasses = ContainerUtil.newArrayList();
myUnknownVariables = ContainerUtil.newTroveSet();
myVariableStates = ContainerUtil.newTroveMap();
myUnknownVariables = ContainerUtil.newLinkedHashSet();
myVariableStates = ContainerUtil.newLinkedHashMap();
myDistinctClasses = new TLongHashSet();
myStack = new Stack<DfaValue>();
}
@@ -73,10 +71,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
myStack = new Stack<DfaValue>(toCopy.myStack);
myDistinctClasses = new TLongHashSet(toCopy.myDistinctClasses.toArray());
myUnknownVariables = new THashSet<DfaVariableValue>(toCopy.myUnknownVariables);
myUnknownVariables = ContainerUtil.newLinkedHashSet(toCopy.myUnknownVariables);
myEqClasses = ContainerUtil.newArrayList(toCopy.myEqClasses);
myVariableStates = new THashMap<DfaVariableValue, DfaVariableState>(toCopy.myVariableStates);
myVariableStates = ContainerUtil.newLinkedHashMap(toCopy.myVariableStates);
myCachedDistinctClassPairs = toCopy.myCachedDistinctClassPairs;
myCachedNonTrivialEqClasses = toCopy.myCachedNonTrivialEqClasses;
@@ -118,22 +116,22 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return myVariableStates.equals(that.myVariableStates);
}
private Set<UnorderedPair<EqClass>> myCachedDistinctClassPairs;
Set<UnorderedPair<EqClass>> getDistinctClassPairs() {
private LinkedHashSet<UnorderedPair<EqClass>> myCachedDistinctClassPairs;
LinkedHashSet<UnorderedPair<EqClass>> getDistinctClassPairs() {
if (myCachedDistinctClassPairs != null) return myCachedDistinctClassPairs;
Set<UnorderedPair<EqClass>> result = ContainerUtil.newHashSet();
LinkedHashSet<UnorderedPair<EqClass>> result = ContainerUtil.newLinkedHashSet();
for (long encodedPair : myDistinctClasses.toArray()) {
result.add(new UnorderedPair<EqClass>(myEqClasses.get(low(encodedPair)), myEqClasses.get(high(encodedPair))));
}
return myCachedDistinctClassPairs = result;
}
private Set<EqClass> myCachedNonTrivialEqClasses;
Set<EqClass> getNonTrivialEqClasses() {
private LinkedHashSet<EqClass> myCachedNonTrivialEqClasses;
LinkedHashSet<EqClass> getNonTrivialEqClasses() {
if (myCachedNonTrivialEqClasses != null) return myCachedNonTrivialEqClasses;
Set<EqClass> result = ContainerUtil.newHashSet();
LinkedHashSet<EqClass> result = ContainerUtil.newLinkedHashSet();
for (EqClass eqClass : myEqClasses) {
if (eqClass != null && eqClass.size() > 1) {
result.add(eqClass);
@@ -42,7 +42,9 @@ import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.usageView.UsageViewTypeLocation;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -192,13 +194,25 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool {
final PsiElement element = refElement.getElement();
final PsiElement nameIdentifier = element != null ? IdentifierUtil.getNameIdentifier(element) : null;
if (nameIdentifier != null) {
final String message;
String quickFixName = "Make " + ElementDescriptionUtil.getElementDescription(element, UsageViewTypeLocation.INSTANCE) + " ";
if (access.equals(PsiModifier.PRIVATE)) {
message = CAN_BE_PRIVATE;
quickFixName += PsiModifier.PRIVATE;
}
else {
if (access.equals(PsiModifier.PACKAGE_LOCAL)) {
message = CAN_BE_PACKAGE_LOCAL;
quickFixName += "package local";
}
else {
message = CAN_BE_PROTECTED;
quickFixName += PsiModifier.PROTECTED;
}
}
return new ProblemDescriptor[]{manager.createProblemDescriptor(nameIdentifier,
access.equals(PsiModifier.PRIVATE)
? CAN_BE_PRIVATE
: access.equals(PsiModifier.PACKAGE_LOCAL)
? CAN_BE_PACKAGE_LOCAL
: CAN_BE_PROTECTED,
new AcceptSuggestedAccess(globalContext.getRefManager(), access),
message,
new AcceptSuggestedAccess(globalContext.getRefManager(), access, quickFixName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)};
}
}
@@ -527,7 +541,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool {
@Override
@Nullable
public QuickFix getQuickFix(final String hint) {
return new AcceptSuggestedAccess(null, hint);
return new AcceptSuggestedAccess(null, hint, null);
}
@Override
@@ -539,22 +553,24 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool {
private static class AcceptSuggestedAccess implements LocalQuickFix{
private final RefManager myManager;
@PsiModifier.ModifierConstant private final String myHint;
private String myName;
private AcceptSuggestedAccess(final RefManager manager, @PsiModifier.ModifierConstant String hint) {
private AcceptSuggestedAccess(final RefManager manager, @PsiModifier.ModifierConstant String hint, String name) {
myManager = manager;
myHint = hint;
myName = name;
}
@Override
@NotNull
public String getName() {
return InspectionsBundle.message("inspection.visibility.accept.quickfix");
return myName != null ? myName : getFamilyName();
}
@Override
@NotNull
public String getFamilyName() {
return getName();
return InspectionsBundle.message("inspection.visibility.accept.quickfix");
}
@Override
@@ -33,7 +33,7 @@ import org.jetbrains.annotations.NonNls;
import java.util.LinkedHashSet;
import java.util.Set;
class JavaWithCastSurrounder extends JavaExpressionSurrounder {
public class JavaWithCastSurrounder extends JavaExpressionSurrounder {
@NonNls private static final String TYPE_TEMPLATE_VARIABLE = "type";
@Override
@@ -27,7 +27,7 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.psi.util.FileTypeUtils;
import org.jetbrains.annotations.NonNls;
class JavaWithIfExpressionSurrounder extends JavaExpressionSurrounder{
public class JavaWithIfExpressionSurrounder extends JavaExpressionSurrounder{
@Override
public boolean isApplicable(PsiExpression expr) {
PsiType type = expr.getType();
@@ -30,8 +30,9 @@ import org.jetbrains.annotations.Nullable;
* @author Maxim.Mossienko
*/
public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiAnnotationParameterList,PsiAnnotationMethod>, DumbAware {
@Nullable
@Override
public @Nullable Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) {
public Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) {
return null;
}
@@ -46,7 +47,7 @@ public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiA
}
@Override
public PsiAnnotationParameterList findElementForParameterInfo(final CreateParameterInfoContext context) {
public PsiAnnotationParameterList findElementForParameterInfo(@NotNull final CreateParameterInfoContext context) {
final PsiAnnotation annotation = ParameterInfoUtils.findParentOfType(context.getFile(), context.getOffset(), PsiAnnotation.class);
if (annotation != null) {
@@ -78,18 +79,18 @@ public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiA
}
@Override
public void showParameterInfo(@NotNull final PsiAnnotationParameterList element, final CreateParameterInfoContext context) {
public void showParameterInfo(@NotNull final PsiAnnotationParameterList element, @NotNull final CreateParameterInfoContext context) {
context.showHint(element, element.getTextRange().getStartOffset() + 1, this);
}
@Override
public PsiAnnotationParameterList findElementForUpdatingParameterInfo(final UpdateParameterInfoContext context) {
public PsiAnnotationParameterList findElementForUpdatingParameterInfo(@NotNull final UpdateParameterInfoContext context) {
final PsiAnnotation annotation = ParameterInfoUtils.findParentOfType(context.getFile(), context.getOffset(), PsiAnnotation.class);
return annotation != null ? annotation.getParameterList() : null;
}
@Override
public void updateParameterInfo(@NotNull final PsiAnnotationParameterList o, final UpdateParameterInfoContext context) {
public void updateParameterInfo(@NotNull final PsiAnnotationParameterList parameterOwner, @NotNull final UpdateParameterInfoContext context) {
CharSequence chars = context.getEditor().getDocument().getCharsSequence();
int offset1 = CharArrayUtil.shiftForward(chars, context.getEditor().getCaretModel().getOffset(), " \t");
final char c = chars.charAt(offset1);
@@ -110,19 +111,17 @@ public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiA
}
@Override
public void updateUI(final PsiAnnotationMethod p, final ParameterInfoUIContext context) {
public void updateUI(final PsiAnnotationMethod p, @NotNull final ParameterInfoUIContext context) {
updateUIText(p, context);
}
public static String updateUIText(PsiAnnotationMethod p, ParameterInfoUIContext context) {
@NonNls StringBuilder buffer = new StringBuilder();
int highlightStartOffset;
int highlightEndOffset;
buffer.append(p.getReturnType().getPresentableText());
buffer.append(" ");
highlightStartOffset = XmlStringUtil.escapeString(buffer.toString()).length();
int highlightStartOffset = XmlStringUtil.escapeString(buffer.toString()).length();
buffer.append(p.getName());
highlightEndOffset = XmlStringUtil.escapeString(buffer.toString()).length();
int highlightEndOffset = XmlStringUtil.escapeString(buffer.toString()).length();
buffer.append("()");
if (p.getDefaultValue() != null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -78,13 +78,13 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
@Override
@Nullable
public PsiExpressionList findElementForParameterInfo(final CreateParameterInfoContext context) {
public PsiExpressionList findElementForParameterInfo(@NotNull final CreateParameterInfoContext context) {
PsiExpressionList argumentList = findArgumentList(context.getFile(), context.getOffset(), context.getParameterListStart());
if (argumentList != null) {
return findMethodsForArgumentList(context, argumentList);
}
return argumentList;
return null;
}
private PsiExpressionList findArgumentList(final PsiFile file, int offset, int parameterStart) {
@@ -112,17 +112,17 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
}
@Override
public void showParameterInfo(@NotNull final PsiExpressionList element, final CreateParameterInfoContext context) {
public void showParameterInfo(@NotNull final PsiExpressionList element, @NotNull final CreateParameterInfoContext context) {
context.showHint(element, element.getTextRange().getStartOffset(), this);
}
@Override
public PsiExpressionList findElementForUpdatingParameterInfo(final UpdateParameterInfoContext context) {
public PsiExpressionList findElementForUpdatingParameterInfo(@NotNull final UpdateParameterInfoContext context) {
return findArgumentList(context.getFile(), context.getOffset(), context.getParameterListStart());
}
@Override
public void updateParameterInfo(@NotNull final PsiExpressionList o, final UpdateParameterInfoContext context) {
public void updateParameterInfo(@NotNull final PsiExpressionList o, @NotNull final UpdateParameterInfoContext context) {
PsiElement parameterOwner = context.getParameterOwner();
if (parameterOwner != o) {
context.removeHint();
@@ -357,7 +357,8 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
}
}
public static String updateMethodPresentation(PsiMethod method, @Nullable PsiSubstitutor substitutor, ParameterInfoUIContext context) {
@NotNull
public static String updateMethodPresentation(@NotNull PsiMethod method, @Nullable PsiSubstitutor substitutor, @NotNull ParameterInfoUIContext context) {
CodeInsightSettings settings = CodeInsightSettings.getInstance();
if (!method.isValid() || substitutor != null && !substitutor.isValid()) {
@@ -444,16 +445,20 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
private static void appendModifierList(@NotNull StringBuilder buffer, @NotNull PsiModifierListOwner owner) {
int lastSize = buffer.length();
for (PsiAnnotation a : AnnotationUtil.getAllAnnotations(owner, false, null)) {
if (lastSize != buffer.length()) buffer.append(" ");
final PsiJavaCodeReferenceElement element = a.getNameReferenceElement();
if (element != null) buffer.append("@").append(element.getReferenceName());
for (PsiAnnotation annotation : AnnotationUtil.getAllAnnotations(owner, false, null)) {
final PsiJavaCodeReferenceElement element = annotation.getNameReferenceElement();
if (element != null) {
final PsiElement resolved = element.resolve();
if (resolved instanceof PsiClass && !AnnotationUtil.isAnnotated((PsiClass)resolved, "java.lang.annotation.Documented", false)) continue;
if (lastSize != buffer.length()) buffer.append(" ");
buffer.append("@").append(element.getReferenceName());
}
}
if (lastSize != buffer.length()) buffer.append(" ");
}
@Override
public void updateUI(final Object p, final ParameterInfoUIContext context) {
public void updateUI(final Object p, @NotNull final ParameterInfoUIContext context) {
if (p instanceof CandidateInfo) {
CandidateInfo info = (CandidateInfo)p;
PsiMethod method = (PsiMethod)info.getElement();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -45,7 +45,7 @@ public class ReferenceParameterInfoHandler implements ParameterInfoHandler<PsiRe
}
@Override
public PsiReferenceParameterList findElementForParameterInfo(final CreateParameterInfoContext context) {
public PsiReferenceParameterList findElementForParameterInfo(@NotNull final CreateParameterInfoContext context) {
final PsiReferenceParameterList referenceParameterList =
ParameterInfoUtils.findParentOfType(context.getFile(), context.getOffset(), PsiReferenceParameterList.class);
@@ -66,18 +66,18 @@ public class ReferenceParameterInfoHandler implements ParameterInfoHandler<PsiRe
}
@Override
public void showParameterInfo(@NotNull final PsiReferenceParameterList element, final CreateParameterInfoContext context) {
public void showParameterInfo(@NotNull final PsiReferenceParameterList element, @NotNull final CreateParameterInfoContext context) {
context.showHint(element, element.getTextRange().getStartOffset() + 1, this);
}
@Override
public PsiReferenceParameterList findElementForUpdatingParameterInfo(final UpdateParameterInfoContext context) {
public PsiReferenceParameterList findElementForUpdatingParameterInfo(@NotNull final UpdateParameterInfoContext context) {
return ParameterInfoUtils.findParentOfType(context.getFile(), context.getOffset(), PsiReferenceParameterList.class);
}
@Override
public void updateParameterInfo(@NotNull final PsiReferenceParameterList o, final UpdateParameterInfoContext context) {
int index = ParameterInfoUtils.getCurrentParameterIndex(o.getNode(), context.getOffset(), JavaTokenType.COMMA);
public void updateParameterInfo(@NotNull final PsiReferenceParameterList parameterOwner, @NotNull final UpdateParameterInfoContext context) {
int index = ParameterInfoUtils.getCurrentParameterIndex(parameterOwner.getNode(), context.getOffset(), JavaTokenType.COMMA);
context.setCurrentParameter(index);
final Object[] objectsToView = context.getObjectsToView();
context.setHighlightedParameter(index < objectsToView.length && index >= 0 ? (PsiElement)objectsToView[index]:null);
@@ -95,7 +95,7 @@ public class ReferenceParameterInfoHandler implements ParameterInfoHandler<PsiRe
}
@Override
public void updateUI(PsiTypeParameter o, ParameterInfoUIContext context) {
public void updateUI(PsiTypeParameter o, @NotNull ParameterInfoUIContext context) {
updateTypeParameter(o, context);
}
@@ -0,0 +1,54 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.completion;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.template.CustomLiveTemplate;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.postfix.templates.PostfixLiveTemplate;
import com.intellij.openapi.editor.Editor;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
import static com.intellij.patterns.StandardPatterns.string;
public class PostfixTemplateCompletionContributor extends CompletionContributor {
private static final TokenSet SUITABLE_ELEMENTS = TokenSet.orSet(ElementType.KEYWORD_BIT_SET,
ElementType.LITERAL_BIT_SET,
TokenSet.create(JavaTokenType.IDENTIFIER));
public PostfixTemplateCompletionContributor() {
extend(CompletionType.BASIC, identifierAfterDot(), new PostfixTemplatesCompletionProvider());
}
@Nullable
public static PostfixLiveTemplate getPostfixLiveTemplate(@NotNull PsiFile file, @NotNull Editor editor) {
PostfixLiveTemplate postfixLiveTemplate = CustomLiveTemplate.EP_NAME.findExtension(PostfixLiveTemplate.class);
return postfixLiveTemplate != null && TemplateManagerImpl.isApplicable(postfixLiveTemplate, editor, file) ? postfixLiveTemplate : null;
}
private static ElementPattern<? extends PsiElement> identifierAfterDot() {
return psiElement().withElementType(SUITABLE_ELEMENTS).afterLeaf(psiElement().withText(string().endsWith(".")));
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.completion;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupActionProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementAction;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesConfigurable;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesListPanel;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.util.Consumer;
import com.intellij.util.PlatformIcons;
public class PostfixTemplateLookupActionProvider implements LookupActionProvider {
@Override
public void fillActions(LookupElement element, final Lookup lookup, Consumer<LookupElementAction> consumer) {
if (element instanceof PostfixTemplateLookupElement) {
final PostfixTemplate template = ((PostfixTemplateLookupElement)element).getPostfixTemplate();
consumer.consume(new LookupElementAction(PlatformIcons.EDIT, "Edit postfix templates settings") {
@Override
public Result performLookupAction() {
final Project project = lookup.getEditor().getProject();
assert project != null;
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (project.isDisposed()) return;
final PostfixTemplatesConfigurable configurable = new PostfixTemplatesConfigurable();
ShowSettingsUtil.getInstance().editConfigurable(project, configurable, new Runnable() {
@Override
public void run() {
PostfixTemplatesListPanel templatesListPanel = configurable.getTemplatesListPanel();
if (templatesListPanel != null) {
templatesListPanel.selectTemplate(template);
}
}
});
}
});
return Result.HIDE_LOOKUP;
}
});
final PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
if (settings != null && settings.isTemplateEnabled(template)) {
consumer.consume(new LookupElementAction(AllIcons.Actions.Delete, String.format("Disable '%s' template", template.getKey())) {
@Override
public Result performLookupAction() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
settings.disableTemplate(template);
}
});
return Result.HIDE_LOOKUP;
}
});
}
}
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.completion;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.impl.LiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.postfix.templates.PostfixLiveTemplate;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import static com.intellij.codeInsight.template.postfix.completion.PostfixTemplateCompletionContributor.getPostfixLiveTemplate;
class PostfixTemplateLookupElement extends LiveTemplateLookupElement {
@NotNull
private final PostfixTemplate myTemplate;
public PostfixTemplateLookupElement(@NotNull PostfixTemplate template, char shortcut) {
super(createStubTemplate(template, shortcut), template.getPresentableName(), true, true);
myTemplate = template;
}
@NotNull
public PostfixTemplate getPostfixTemplate() {
return myTemplate;
}
@Override
public void renderElement(LookupElementPresentation presentation) {
super.renderElement(presentation);
presentation.setTailText(" " + arrow() + " " + myTemplate.getExample());
}
@Override
public void handleInsert(InsertionContext context) {
context.setAddCompletionChar(false);
int lengthOfTypedKey = context.getTailOffset() - context.getStartOffset();
String templateKey = myTemplate.getKey();
Editor editor = context.getEditor();
if (lengthOfTypedKey < templateKey.length()) {
context.getDocument().insertString(context.getTailOffset(), templateKey.substring(lengthOfTypedKey));
editor.getCaretModel().moveToOffset(context.getTailOffset() + templateKey.length() - lengthOfTypedKey);
}
PsiFile file = context.getFile();
PostfixLiveTemplate postfixLiveTemplate = getPostfixLiveTemplate(context.getFile(), context.getEditor());
if (postfixLiveTemplate != null) {
postfixLiveTemplate.expand(templateKey, new CustomTemplateCallback(editor, file, false));
}
}
private static TemplateImpl createStubTemplate(@NotNull PostfixTemplate postfixTemplate, char shortcut) {
TemplateImpl template = new TemplateImpl(postfixTemplate.getKey(), "postfixTemplate");
template.setShortcutChar(shortcut);
return template;
}
private static String arrow() {
return SystemInfo.isMac ? "→" :"->";
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.completion;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionProvider;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
import com.intellij.codeInsight.template.postfix.templates.PostfixLiveTemplate;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.StandardPatterns;
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import static com.intellij.codeInsight.template.postfix.completion.PostfixTemplateCompletionContributor.getPostfixLiveTemplate;
class PostfixTemplatesCompletionProvider extends CompletionProvider<CompletionParameters> {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
if (!isCompletionEnabled(parameters)) {
return;
}
PostfixLiveTemplate postfixLiveTemplate = getPostfixLiveTemplate(parameters.getOriginalFile(), parameters.getEditor());
if (postfixLiveTemplate != null) {
PsiFile file = parameters.getPosition().getContainingFile();
final CustomTemplateCallback callback = new CustomTemplateCallback(parameters.getEditor(), file, false);
String computedKey = postfixLiveTemplate.computeTemplateKey(callback);
if (computedKey != null) {
PostfixTemplate template = postfixLiveTemplate.getTemplateByKey(computedKey);
if (template != null) {
result = result.withPrefixMatcher(computedKey);
result.addElement(new PostfixTemplateLookupElement(template, postfixLiveTemplate.getShortcut()));
}
}
CharSequence documentContent = parameters.getEditor().getDocument().getCharsSequence();
String possibleKey = postfixLiveTemplate.computeTemplateKeyWithoutContextChecking(documentContent, parameters.getOffset());
if (StringUtil.isNotEmpty(possibleKey)) {
result = result.withPrefixMatcher(possibleKey);
result.restartCompletionOnPrefixChange(StandardPatterns.string().startsWith(possibleKey));
}
}
}
private static boolean isCompletionEnabled(@NotNull CompletionParameters parameters) {
if (!parameters.isAutoPopup()) {
return false;
}
PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
if (settings == null || !settings.isPostfixTemplatesEnabled() || !settings.isTemplatesCompletionEnabled()) {
return false;
}
return true;
}
}
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesConfigurable">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="f9f95" class="com.intellij.ui.components.JBCheckBox" binding="myPostfixTemplatesEnabled">
<constraints>
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="1" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&amp;Enable postfix templates"/>
</properties>
</component>
<grid id="a9fc9" binding="myTemplatesListPanelContainer" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
<component id="9f784" class="com.intellij.ui.components.JBCheckBox" binding="myCompletionEnabledCheckbox">
<constraints>
<grid row="1" column="0" row-span="1" col-span="2" vsize-policy="1" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&amp;Show postfix templates in completion autopopup"/>
</properties>
</component>
<component id="2231a" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="1" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Expand templates with"/>
</properties>
</component>
<component id="63d6b" class="com.intellij.openapi.ui.ComboBox" binding="myShortcutComboBox">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<model/>
</properties>
</component>
</children>
</grid>
</form>
@@ -0,0 +1,184 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.settings;
import com.intellij.application.options.editor.EditorOptionsProvider;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.util.Arrays;
import java.util.Map;
public class PostfixTemplatesConfigurable implements SearchableConfigurable, EditorOptionsProvider, Configurable.NoScroll {
@Nullable
private PostfixTemplatesListPanel myTemplatesListPanel;
@NotNull
private final PostfixTemplatesSettings myTemplatesSettings;
private JComponent myPanel;
private JBCheckBox myCompletionEnabledCheckbox;
private JBCheckBox myPostfixTemplatesEnabled;
private JPanel myTemplatesListPanelContainer;
private ComboBox myShortcutComboBox;
private static final String SPACE = CodeInsightBundle.message("template.shortcut.space");
private static final String TAB = CodeInsightBundle.message("template.shortcut.tab");
private static final String ENTER = CodeInsightBundle.message("template.shortcut.enter");
@SuppressWarnings("unchecked")
public PostfixTemplatesConfigurable() {
PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
if (settings == null) {
throw new RuntimeException("Can't retrieve postfix template settings");
}
myTemplatesSettings = settings;
myTemplatesListPanel = new PostfixTemplatesListPanel(Arrays.asList(PostfixTemplate.EP_NAME.getExtensions()));
myTemplatesListPanelContainer.setLayout(new BorderLayout());
myTemplatesListPanelContainer.add(myTemplatesListPanel.getComponent(), BorderLayout.CENTER);
myPostfixTemplatesEnabled.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
updateComponents();
}
});
myShortcutComboBox.addItem(TAB);
myShortcutComboBox.addItem(SPACE);
myShortcutComboBox.addItem(ENTER);
}
@NotNull
@Override
public String getId() {
return "reference.settingsdialog.IDE.editor.postfix.templates";
}
@Nullable
@Override
public String getHelpTopic() {
return null;
}
@Nls
@Override
public String getDisplayName() {
return "Postfix Templates";
}
@Nullable
public PostfixTemplatesListPanel getTemplatesListPanel() {
return myTemplatesListPanel;
}
@NotNull
@Override
public JComponent createComponent() {
return myPanel;
}
@Override
public void apply() throws ConfigurationException {
if (myTemplatesListPanel != null) {
Map<String, Boolean> newTemplatesState = ContainerUtil.newHashMap();
for (Map.Entry<String, Boolean> entry : myTemplatesListPanel.getState().entrySet()) {
Boolean value = entry.getValue();
if (value != null && !value) {
newTemplatesState.put(entry.getKey(), entry.getValue());
}
}
myTemplatesSettings.setTemplatesState(newTemplatesState);
myTemplatesSettings.setPostfixTemplatesEnabled(myPostfixTemplatesEnabled.isSelected());
myTemplatesSettings.setTemplatesCompletionEnabled(myCompletionEnabledCheckbox.isSelected());
myTemplatesSettings.setShortcut(stringToShortcut((String)myShortcutComboBox.getSelectedItem()));
}
}
@Override
public void reset() {
if (myTemplatesListPanel != null) {
myTemplatesListPanel.setState(myTemplatesSettings.getTemplatesState());
myPostfixTemplatesEnabled.setSelected(myTemplatesSettings.isPostfixTemplatesEnabled());
myCompletionEnabledCheckbox.setSelected(myTemplatesSettings.isTemplatesCompletionEnabled());
myShortcutComboBox.setSelectedItem(shortcutToString((char)myTemplatesSettings.getShortcut()));
updateComponents();
}
}
@Override
public boolean isModified() {
if (myTemplatesListPanel == null) {
return false;
}
return myPostfixTemplatesEnabled.isSelected() != myTemplatesSettings.isPostfixTemplatesEnabled() ||
myCompletionEnabledCheckbox.isSelected() != myTemplatesSettings.isTemplatesCompletionEnabled() ||
stringToShortcut((String)myShortcutComboBox.getSelectedItem()) != myTemplatesSettings.getShortcut() ||
!myTemplatesListPanel.getState().equals(myTemplatesSettings.getTemplatesState());
}
@Override
public void disposeUIResources() {
myTemplatesListPanel = null;
}
@Nullable
@Override
public Runnable enableSearch(String s) {
return null;
}
private void updateComponents() {
boolean pluginEnabled = myPostfixTemplatesEnabled.isSelected();
myCompletionEnabledCheckbox.setEnabled(pluginEnabled);
myShortcutComboBox.setEnabled(pluginEnabled);
if (myTemplatesListPanel != null) {
myTemplatesListPanel.setEnabled(pluginEnabled);
}
}
private static char stringToShortcut(@NotNull String string) {
if (SPACE.equals(string)) {
return TemplateSettings.SPACE_CHAR;
}
else if (ENTER.equals(string)) {
return TemplateSettings.ENTER_CHAR;
}
return TemplateSettings.TAB_CHAR;
}
private static String shortcutToString(char shortcut) {
if (shortcut == TemplateSettings.SPACE_CHAR) {
return SPACE;
}
if (shortcut == TemplateSettings.ENTER_CHAR) {
return ENTER;
}
return TAB;
}
}
@@ -0,0 +1,207 @@
package com.intellij.codeInsight.template.postfix.settings;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.ui.BooleanTableCellEditor;
import com.intellij.ui.BooleanTableCellRenderer;
import com.intellij.ui.TableViewSpeedSearch;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.table.TableView;
import com.intellij.util.Function;
import com.intellij.util.NotNullFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class PostfixTemplatesListPanel {
private static final NotNullFunction<PostfixTemplate, String> GET_SHORTCUT_FUNCTION =
new NotNullFunction<PostfixTemplate, String>() {
@NotNull
@Override
public String fun(@NotNull PostfixTemplate template) {
return template.getKey();
}
};
private static final NotNullFunction<PostfixTemplate, String> GET_DESCRIPTION_FUNCTION =
new NotNullFunction<PostfixTemplate, String>() {
@NotNull
@Override
public String fun(@NotNull PostfixTemplate template) {
return template.getDescription();
}
};
private static final NotNullFunction<PostfixTemplate, String> GET_EXAMPLE_FUNCTION =
new NotNullFunction<PostfixTemplate, String>() {
@NotNull
@Override
public String fun(@NotNull PostfixTemplate template) {
return template.getExample();
}
};
@NotNull private final Map<String, Boolean> myTemplatesState = ContainerUtil.newHashMap();
@NotNull private final JPanel myPanelWithTableView;
private final TableView<PostfixTemplate> myTemplatesTableView;
public PostfixTemplatesListPanel(@NotNull List<PostfixTemplate> templates) {
ColumnInfo[] columns = generateColumns(templates);
ListTableModel<PostfixTemplate> templatesTableModel = new ListTableModel<PostfixTemplate>(columns, templates, 0);
myTemplatesTableView = new TableView<PostfixTemplate>();
myTemplatesTableView.setModelAndUpdateColumns(templatesTableModel);
myTemplatesTableView.setShowGrid(false);
myTemplatesTableView.setStriped(true);
myTemplatesTableView.setBorder(null);
new TableViewSpeedSearch<PostfixTemplate>(myTemplatesTableView) {
@Override
protected String getItemText(@NotNull PostfixTemplate template) {
return template.getPresentableName();
}
};
myPanelWithTableView = ToolbarDecorator.createDecorator(myTemplatesTableView)
.setAsUsualTopToolbar()
.disableAddAction()
.disableRemoveAction()
.disableUpDownActions().createPanel();
}
@NotNull
private ColumnInfo[] generateColumns(@NotNull List<PostfixTemplate> templates) {
String longestTemplateName = "";
String longestDescription = "";
String longestExample = "";
for (PostfixTemplate template : templates) {
longestTemplateName = longestString(longestTemplateName, GET_SHORTCUT_FUNCTION.fun(template));
longestDescription = longestString(longestDescription, GET_DESCRIPTION_FUNCTION.fun(template));
longestExample = longestString(longestExample, GET_EXAMPLE_FUNCTION.fun(template));
}
return new ColumnInfo[]{
new BooleanColumnInfo(),
new StringColumnInfo("Shortcut", GET_SHORTCUT_FUNCTION, longestTemplateName),
new StringColumnInfo("Description", GET_DESCRIPTION_FUNCTION, longestDescription),
new StringColumnInfo("Example", GET_EXAMPLE_FUNCTION, longestExample),
};
}
public void selectTemplate(@NotNull PostfixTemplate template) {
myTemplatesTableView.setSelection(Arrays.asList(template));
}
@NotNull
private static String longestString(@NotNull String firstString, @NotNull String secondString) {
return secondString.length() > firstString.length() ? secondString : firstString;
}
@NotNull
public JPanel getComponent() {
return myPanelWithTableView;
}
public void setState(@NotNull Map<String, Boolean> templatesState) {
myTemplatesState.clear();
for (Map.Entry<String, Boolean> entry : templatesState.entrySet()) {
myTemplatesState.put(entry.getKey(), entry.getValue());
}
}
@NotNull
public Map<String, Boolean> getState() {
return myTemplatesState;
}
public void setEnabled(boolean enabled) {
myTemplatesTableView.setEnabled(enabled);
}
private class BooleanColumnInfo extends ColumnInfo<PostfixTemplate, Boolean> {
private final BooleanTableCellRenderer CELL_RENDERER = new BooleanTableCellRenderer();
private final BooleanTableCellEditor CELL_EDITOR = new BooleanTableCellEditor();
private final int WIDTH = new JBCheckBox().getPreferredSize().width + 4;
public BooleanColumnInfo() {
super("");
}
@Nullable
@Override
public TableCellRenderer getRenderer(PostfixTemplate template) {
return CELL_RENDERER;
}
@Nullable
@Override
public TableCellEditor getEditor(PostfixTemplate template) {
return CELL_EDITOR;
}
@Override
public int getWidth(JTable table) {
return WIDTH;
}
@NotNull
@Override
public Class getColumnClass() {
return Boolean.class;
}
@Override
public boolean isCellEditable(PostfixTemplate template) {
return myTemplatesTableView.isEnabled();
}
@Nullable
@Override
public Boolean valueOf(@NotNull PostfixTemplate template) {
return ContainerUtil.getOrElse(myTemplatesState, template.getKey(), true);
}
@Override
public void setValue(@NotNull PostfixTemplate template, Boolean value) {
myTemplatesState.put(template.getKey(), value);
}
}
private static class StringColumnInfo extends ColumnInfo<PostfixTemplate, String> {
@NotNull private final Function<PostfixTemplate, String> myValueOfFunction;
@Nullable private final String myPreferredStringValue;
public StringColumnInfo(@NotNull String name,
@NotNull Function<PostfixTemplate, String> valueOfFunction,
@Nullable String preferredStringValue) {
super(name);
myValueOfFunction = valueOfFunction;
boolean hasValue = preferredStringValue != null && !preferredStringValue.isEmpty();
myPreferredStringValue = hasValue ? preferredStringValue : null;
}
@Override
public int getAdditionalWidth() {
return UIUtil.DEFAULT_HGAP;
}
@Nullable
@Override
public String getPreferredStringValue() {
return myPreferredStringValue;
}
public String valueOf(final PostfixTemplate template) {
return myValueOfFunction.fun(template);
}
}
}
@@ -0,0 +1,111 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.settings;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.XmlSerializerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Map;
@State(
name = "PostfixTemplatesSettings",
storages = {
@Storage(file = StoragePathMacros.APP_CONFIG + "/postfixTemplates.xml")
}
)
public class PostfixTemplatesSettings implements PersistentStateComponent<PostfixTemplatesSettings>, ExportableComponent {
@NotNull
private Map<String, Boolean> myTemplatesState = ContainerUtil.newHashMap();
private boolean postfixTemplatesEnabled = true;
private boolean templatesCompletionEnabled = true;
private int myShortcut = TemplateSettings.TAB_CHAR;
public boolean isTemplateEnabled(@NotNull PostfixTemplate template) {
return ContainerUtil.getOrElse(myTemplatesState, template.getKey(), true);
}
public void disableTemplate(@NotNull PostfixTemplate template) {
myTemplatesState.put(template.getKey(), Boolean.FALSE);
}
public boolean isPostfixTemplatesEnabled() {
return postfixTemplatesEnabled;
}
public void setPostfixTemplatesEnabled(boolean postfixTemplatesEnabled) {
this.postfixTemplatesEnabled = postfixTemplatesEnabled;
}
public boolean isTemplatesCompletionEnabled() {
return templatesCompletionEnabled;
}
public void setTemplatesCompletionEnabled(boolean templatesCompletionEnabled) {
this.templatesCompletionEnabled = templatesCompletionEnabled;
}
@NotNull
public Map<String, Boolean> getTemplatesState() {
return myTemplatesState;
}
public void setTemplatesState(@NotNull Map<String, Boolean> templatesState) {
myTemplatesState = templatesState;
}
public int getShortcut() {
return myShortcut;
}
public void setShortcut(int shortcut) {
myShortcut = shortcut;
}
@Nullable
public static PostfixTemplatesSettings getInstance() {
return ServiceManager.getService(PostfixTemplatesSettings.class);
}
@Nullable
@Override
public PostfixTemplatesSettings getState() {
return this;
}
@Override
public void loadState(PostfixTemplatesSettings settings) {
XmlSerializerUtil.copyBean(settings, this);
}
@NotNull
@Override
public File[] getExportFiles() {
return new File[]{PathManager.getOptionsFile("postfixCompletion.xml")};
}
@NotNull
@Override
public String getPresentableName() {
return "Postfix Completion";
}
}
@@ -0,0 +1,17 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
public class AssertStatementPostfixTemplate extends BooleanPostfixTemplate {
public AssertStatementPostfixTemplate() {
super("assert", "Creates assertion from boolean expression", "assert expr;");
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PostfixTemplatesUtils.createSimpleStatement(context, editor, "assert");
}
}
@@ -0,0 +1,22 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionStatement;
import org.jetbrains.annotations.NotNull;
abstract public class BooleanPostfixTemplate extends PostfixTemplate {
protected BooleanPostfixTemplate(@NotNull String name, @NotNull String description, @NotNull String example) {
super(name, description, example);
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression topmostExpression = getTopmostExpression(context);
return topmostExpression != null &&
topmostExpression.getParent() instanceof PsiExpressionStatement &&
PostfixTemplatesUtils.isBoolean(topmostExpression.getType());
}
}
@@ -0,0 +1,18 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.generation.surroundWith.JavaWithCastSurrounder;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiExpression;
import org.jetbrains.annotations.NotNull;
public class CastExpressionPostfixTemplate extends ExpressionPostfixTemplateWithChooser {
public CastExpressionPostfixTemplate() {
super("cast", "Surrounds expression with cast", "((SomeType) expr)");
}
@Override
protected void doIt(@NotNull final Editor editor, @NotNull final PsiExpression expression) {
PostfixTemplatesUtils.apply(new JavaWithCastSurrounder(), expression.getProject(), editor, expression);
}
}
@@ -0,0 +1,26 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.CodeInsightServicesUtil;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import org.jetbrains.annotations.NotNull;
public class ElseStatementPostfixTemplate extends BooleanPostfixTemplate {
public ElseStatementPostfixTemplate() {
super("else", "Checks boolean expression to be 'false'", "if (!expr)");
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expression = getTopmostExpression(context);
assert expression != null;
PsiExpression invertedExpression = (PsiExpression)expression.replace(CodeInsightServicesUtil.invertCondition(expression));
TextRange range = PostfixTemplatesUtils.ifStatement(invertedExpression.getProject(), editor, invertedExpression);
if (range != null) {
editor.getCaretModel().moveToOffset(range.getStartOffset());
}
}
}
@@ -0,0 +1,88 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.codeInsight.unwrap.ScopeHighlighter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiExpressionTrimRenderer;
import com.intellij.refactoring.IntroduceTargetChooser;
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author ignatov
*/
public abstract class ExpressionPostfixTemplateWithChooser extends PostfixTemplate {
protected ExpressionPostfixTemplateWithChooser(@NotNull String name, @NotNull String description, @NotNull String example) {
super(name, description, example);
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
return !getExpressions(context, copyDocument, newOffset).isEmpty();
}
@Override
public void expand(@NotNull PsiElement context, @NotNull final Editor editor) {
List<PsiExpression> expressions = getExpressions(context, editor.getDocument(), editor.getCaretModel().getOffset());
if (expressions.isEmpty()) {
PostfixTemplatesUtils.showErrorHint(context.getProject(), editor);
}
else if (expressions.size() == 1) {
doIt(editor, expressions.get(0));
}
else {
IntroduceTargetChooser.showChooser(
editor, expressions,
new Pass<PsiExpression>() {
public void pass(@NotNull final PsiExpression e) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().executeCommand(e.getProject(), new Runnable() {
public void run() {
doIt(editor, e);
}
}, "Expand postfix template", PostfixLiveTemplate.POSTFIX_TEMPLATE_ID);
}
});
}
},
new PsiExpressionTrimRenderer.RenderFunction(),
"Expressions", 0, ScopeHighlighter.NATURAL_RANGER);
}
}
@NotNull
protected List<PsiExpression> getExpressions(@NotNull PsiElement context, @NotNull Document document, int offset) {
List<PsiExpression> expressions = IntroduceVariableBase.collectExpressions(context.getContainingFile(), document, offset, false);
return ContainerUtil.filter(expressions.isEmpty() ? maybeTopmostExpression(context) : expressions, getTypeCondition());
}
@NotNull
@SuppressWarnings("unchecked")
protected Condition<PsiExpression> getTypeCondition() {
return Condition.TRUE;
}
@NotNull
private static List<PsiExpression> maybeTopmostExpression(@NotNull PsiElement context) {
PsiExpression expression = getTopmostExpression(context);
PsiType type = expression != null ? expression.getType() : null;
if (type == null || PsiType.VOID.equals(type)) return ContainerUtil.emptyList();
return ContainerUtil.createMaybeSingletonList(expression);
}
protected abstract void doIt(@NotNull Editor editor, @NotNull PsiExpression expression);
}
@@ -0,0 +1,31 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ForAscendingPostfixTemplate extends ForIndexedPostfixTemplate {
public ForAscendingPostfixTemplate() {
super("fori", "Iterates with index over collection", "for (int i = 0; i < expr.length; i++)");
}
@Override
@NotNull
protected String getOperator() {
return "++";
}
@NotNull
@Override
protected String getComparativeSign(@NotNull PsiExpression expr) {
return "<";
}
@Nullable
@Override
protected Pair<String, String> calculateBounds(@NotNull PsiExpression expression) {
String bound = getExpressionBound(expression);
return bound != null ? Pair.create("0", bound) : null;
}
}
@@ -0,0 +1,37 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ForDescendingPostfixTemplate extends ForIndexedPostfixTemplate {
public ForDescendingPostfixTemplate() {
super("forr", "Iterates with index in reverse order", "for (int i = expr.length-1; i >= 0; i--)");
}
@Override
@NotNull
protected String getOperator() {
return "--";
}
@NotNull
@Override
protected String getComparativeSign(@NotNull PsiExpression expr) {
return PostfixTemplatesUtils.isNumber(expr.getType()) ? ">" : ">=";
}
@Nullable
@Override
protected Pair<String, String> calculateBounds(@NotNull PsiExpression expression) {
String bound = getExpressionBound(expression);
if (bound == null) {
return null;
}
return PostfixTemplatesUtils.isNumber(expression.getType())
? Pair.create(bound, "0")
: Pair.create(bound + " - 1", "0");
}
}
@@ -0,0 +1,103 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.codeInsight.template.impl.MacroCallNode;
import com.intellij.codeInsight.template.macro.SuggestVariableNameMacro;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionStatement;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class ForIndexedPostfixTemplate extends PostfixTemplate {
protected ForIndexedPostfixTemplate(@NotNull String key, @NotNull String description, @NotNull String example) {
super(key, description, example);
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression expr = getTopmostExpression(context);
if (expr == null || !(expr.getParent() instanceof PsiExpressionStatement)) return false;
return PostfixTemplatesUtils.isNumber(expr.getType()) || PostfixTemplatesUtils.isArray(expr.getType()) || PostfixTemplatesUtils
.isIterable(expr.getType());
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expr = getTopmostExpression(context);
if (expr == null) {
PostfixTemplatesUtils.showErrorHint(context.getProject(), editor);
return;
}
Pair<String, String> bounds = calculateBounds(expr);
if (bounds == null) {
PostfixTemplatesUtils.showErrorHint(context.getProject(), editor);
return;
}
Project project = context.getProject();
Document document = editor.getDocument();
document.deleteString(expr.getTextRange().getStartOffset(), expr.getTextRange().getEndOffset());
TemplateManager manager = TemplateManager.getInstance(project);
Template template = manager.createTemplate("", "");
template.setToReformat(true);
template.addTextSegment("for (" + suggestIndexType(expr) + " ");
MacroCallNode index = new MacroCallNode(new SuggestVariableNameMacro());
String indexVariable = "index";
template.addVariable(indexVariable, index, index, true);
template.addTextSegment(" = " + bounds.first + "; ");
template.addVariableSegment(indexVariable);
template.addTextSegment(getComparativeSign(expr));
template.addTextSegment(bounds.second);
template.addTextSegment("; ");
template.addVariableSegment(indexVariable);
template.addTextSegment(getOperator());
template.addTextSegment(") {\n");
template.addEndVariable();
template.addTextSegment("\n}");
manager.startTemplate(editor, template);
}
@NotNull
protected abstract String getComparativeSign(@NotNull PsiExpression expr);
@Nullable
protected abstract Pair<String, String> calculateBounds(@NotNull PsiExpression expression);
@NotNull
protected abstract String getOperator();
@Nullable
protected static String getExpressionBound(@NotNull PsiExpression expr) {
PsiType type = expr.getType();
if (PostfixTemplatesUtils.isNumber(type)) {
return expr.getText();
}
else if (PostfixTemplatesUtils.isArray(type)) {
return expr.getText() + ".length";
}
else if (PostfixTemplatesUtils.isIterable(type)) {
return expr.getText() + ".size()";
}
return null;
}
@NotNull
private static String suggestIndexType(@NotNull PsiExpression expr) {
PsiType type = expr.getType();
if (PostfixTemplatesUtils.isNumber(type)) {
return type.getCanonicalText();
}
return "int";
}
}
@@ -0,0 +1,62 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.codeInsight.template.impl.MacroCallNode;
import com.intellij.codeInsight.template.impl.TextExpression;
import com.intellij.codeInsight.template.impl.VariableNode;
import com.intellij.codeInsight.template.macro.IterableComponentTypeMacro;
import com.intellij.codeInsight.template.macro.SuggestVariableNameMacro;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionStatement;
import org.jetbrains.annotations.NotNull;
public class ForeachPostfixTemplate extends PostfixTemplate {
public ForeachPostfixTemplate() {
super("for", "Iterates over enumerable collection", "for (T item : collection)");
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression expr = getTopmostExpression(context);
if (expr == null || !(expr.getParent() instanceof PsiExpressionStatement)) return false;
return PostfixTemplatesUtils.isArray(expr.getType()) || PostfixTemplatesUtils.isIterable(expr.getType());
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expr = getTopmostExpression(context);
if (expr == null) return;
Project project = context.getProject();
Document document = editor.getDocument();
document.deleteString(expr.getTextRange().getStartOffset(), expr.getTextRange().getEndOffset());
TemplateManager manager = TemplateManager.getInstance(project);
Template template = manager.createTemplate("", "");
template.setToReformat(true);
template.addTextSegment("for (");
MacroCallNode type = new MacroCallNode(new IterableComponentTypeMacro());
String variable = "variable";
type.addParameter(new VariableNode(variable, null));
MacroCallNode name = new MacroCallNode(new SuggestVariableNameMacro());
template.addVariable("type", type, type, false);
template.addTextSegment(" ");
template.addVariable("name", name, name, true);
template.addTextSegment(" : ");
template.addVariable(variable, new TextExpression(expr.getText()), false);
template.addTextSegment(") {\n");
template.addEndVariable();
template.addTextSegment("\n}");
manager.startTemplate(editor, template);
}
}
@@ -0,0 +1,25 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import org.jetbrains.annotations.NotNull;
public class IfStatementPostfixTemplate extends BooleanPostfixTemplate {
public IfStatementPostfixTemplate() {
super("if", "Checks boolean expression to be 'true'", "if (expr)");
}
@Override
public void expand(@NotNull PsiElement context, @NotNull final Editor editor) {
PsiExpression expression = getTopmostExpression(context);
assert expression != null;
TextRange range = PostfixTemplatesUtils.ifStatement(expression.getProject(), editor, expression);
if (range != null) {
editor.getCaretModel().moveToOffset(range.getStartOffset());
}
}
}
@@ -0,0 +1,108 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.guess.GuessManager;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
import com.intellij.codeInsight.template.*;
import com.intellij.codeInsight.template.postfix.util.Aliases;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashSet;
import java.util.Set;
@Aliases(".inst")
public class InstanceofExpressionPostfixTemplate extends PostfixTemplate {
public InstanceofExpressionPostfixTemplate() {
super("instanceof", "Surrounds expression with instanceof", "expr instanceof SomeType ? ((SomeType) expr). : null");
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
return getTopmostExpression(context) != null;
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expression = getTopmostExpression(context);
if (expression == null) return;
surroundExpression(context.getProject(), editor, expression);
}
private static void surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException {
assert expr.isValid();
PsiType[] types = GuessManager.getInstance(project).guessTypeToCast(expr);
final boolean parenthesesNeeded = expr instanceof PsiPolyadicExpression ||
expr instanceof PsiConditionalExpression ||
expr instanceof PsiAssignmentExpression;
String exprText = parenthesesNeeded ? "(" + expr.getText() + ")" : expr.getText();
Template template = generateTemplate(project, exprText, types);
TextRange range;
if (expr.isPhysical()) {
range = expr.getTextRange();
}
else {
RangeMarker rangeMarker = expr.getUserData(ElementToWorkOn.TEXT_RANGE);
if (rangeMarker == null) {
PostfixTemplatesUtils.showErrorHint(project, editor);
return;
}
range = new TextRange(rangeMarker.getStartOffset(), rangeMarker.getEndOffset());
}
editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset());
editor.getCaretModel().moveToOffset(range.getStartOffset());
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
TemplateManager.getInstance(project).startTemplate(editor, template);
}
private static Template generateTemplate(Project project, String exprText, PsiType[] suggestedTypes) {
TemplateManager templateManager = TemplateManager.getInstance(project);
Template template = templateManager.createTemplate("", "");
template.setToReformat(true);
Set<LookupElement> itemSet = new LinkedHashSet<LookupElement>();
for (PsiType type : suggestedTypes) {
itemSet.add(PsiTypeLookupItem.createLookupItem(type, null));
}
final LookupElement[] lookupItems = itemSet.toArray(new LookupElement[itemSet.size()]);
final Result result = suggestedTypes.length > 0 ? new PsiTypeResult(suggestedTypes[0], project) : null;
Expression expr = new Expression() {
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
return lookupItems.length > 1 ? lookupItems : null;
}
@Override
public Result calculateResult(ExpressionContext context) {
return result;
}
@Override
public Result calculateQuickResult(ExpressionContext context) {
return null;
}
};
template.addTextSegment(exprText);
template.addTextSegment(" instanceof ");
String type = "type";
template.addVariable(type, expr, expr, true);
template.addTextSegment(" ? ((");
template.addVariableSegment(type);
template.addTextSegment(")" + exprText + ")");
template.addEndVariable();
template.addTextSegment(" : null;");
return template;
}
}
@@ -0,0 +1,40 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.introduceField.IntroduceFieldHandler;
import org.jetbrains.annotations.NotNull;
public class IntroduceFieldPostfixTemplate extends ExpressionPostfixTemplateWithChooser {
public IntroduceFieldPostfixTemplate() {
super("field", "Introduces field for expression", "myField = expr;");
}
@Override
protected void doIt(@NotNull Editor editor, @NotNull PsiExpression expression) {
IntroduceFieldHandler handler = ApplicationManager.getApplication().isUnitTestMode() ? getMockHandler(expression) : new IntroduceFieldHandler();
handler.invoke(expression.getProject(), new PsiElement[]{expression}, null);
}
@NotNull
private static IntroduceFieldHandler getMockHandler(@NotNull final PsiExpression expression) {
final PsiClass containingClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
assert containingClass != null;
return new IntroduceFieldHandler() {
// mock default settings
@Override
protected Settings showRefactoringDialog(Project project, Editor editor, PsiClass parentClass,
PsiExpression expr, PsiType type, PsiExpression[] occurrences,
PsiElement anchorElement, PsiElement anchorElementIfAll) {
return new Settings(
"foo", expression, PsiExpression.EMPTY_ARRAY, false, false, false,
InitializationPlace.IN_CURRENT_METHOD, PsiModifier.PRIVATE, null,
null, false, containingClass, false, false);
}
};
}
}
@@ -0,0 +1,72 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.introduceVariable.InputValidator;
import com.intellij.refactoring.introduceVariable.IntroduceVariableHandler;
import com.intellij.refactoring.introduceVariable.IntroduceVariableSettings;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import org.jetbrains.annotations.NotNull;
// todo: support for int[].var (parses as .class access!)
public class IntroduceVariablePostfixTemplate extends ExpressionPostfixTemplateWithChooser {
public IntroduceVariablePostfixTemplate() {
super("var", "Introduces variable for expression", "T name = expr;");
}
@Override
protected void doIt(@NotNull Editor editor, @NotNull PsiExpression expression) {
// for advanced stuff use ((PsiJavaCodeReferenceElement)expression).advancedResolve(true).getElement();
IntroduceVariableHandler handler = ApplicationManager.getApplication().isUnitTestMode() ? getMockHandler() : new IntroduceVariableHandler();
handler.invoke(expression.getProject(), editor, expression);
}
@NotNull
private static IntroduceVariableHandler getMockHandler() {
return new IntroduceVariableHandler() {
// mock default settings
@Override
public final IntroduceVariableSettings getSettings(Project project, Editor editor, final PsiExpression expr,
PsiExpression[] occurrences, TypeSelectorManagerImpl typeSelectorManager,
boolean declareFinalIfAll, boolean anyAssignmentLHS, InputValidator validator,
PsiElement anchor, OccurrencesChooser.ReplaceChoice replaceChoice) {
return new IntroduceVariableSettings() {
@Override
public String getEnteredName() {
return "foo";
}
@Override
public boolean isReplaceAllOccurrences() {
return false;
}
@Override
public boolean isDeclareFinal() {
return false;
}
@Override
public boolean isReplaceLValues() {
return false;
}
@Override
public PsiType getSelectedType() {
return expr.getType();
}
@Override
public boolean isOK() {
return true;
}
};
}
};
}
}
@@ -0,0 +1,15 @@
package com.intellij.codeInsight.template.postfix.templates;
import org.jetbrains.annotations.NotNull;
public class IsNullCheckPostfixTemplate extends NullCheckPostfixTemplate {
public IsNullCheckPostfixTemplate() {
super("null", "Checks expression to be null", "if (expr == null)");
}
@NotNull
@Override
protected String getTail() {
return "== null";
}
}
@@ -0,0 +1,102 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class NewExpressionPostfixTemplate extends PostfixTemplate {
public NewExpressionPostfixTemplate() {
super("new", "Produces instantiation expression for type", "new SomeType()");
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
// todo: copy paste?
PsiElement ref = PsiTreeUtil.getParentOfType(context, PsiJavaCodeReferenceElement.class);
if (ref instanceof PsiJavaReference) {
PsiElement element = ((PsiJavaReference)ref).advancedResolve(true).getElement();
if (element instanceof PsiClass) {
PsiClass psiClass = (PsiClass)element;
CtorAccessibility accessibility = calcAccessibility(psiClass, context);
if (accessibility != CtorAccessibility.NOT_ACCESSIBLE) return true;
}
}
return false;
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiElement ref = PsiTreeUtil.getParentOfType(context, PsiJavaCodeReferenceElement.class);
if (ref instanceof PsiJavaReference) {
PsiElement element = ((PsiJavaReference)ref).advancedResolve(true).getElement();
if (element instanceof PsiClass) {
PsiClass psiClass = (PsiClass)element;
CtorAccessibility accessibility = calcAccessibility(psiClass, context);
if (accessibility != CtorAccessibility.NOT_ACCESSIBLE) {
boolean typeRequiresRefinement = psiClass.isInterface() || psiClass.hasModifierProperty(PsiModifier.ABSTRACT);
String template = "new " + ref.getText() + "()";
if (typeRequiresRefinement) template += "{}";
PsiElementFactory factory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
PsiNewExpression newExpression = (PsiNewExpression)factory.createExpressionFromText(template, context);
PsiElement replace = ref.getParent().replace(newExpression);
replace.getNode().addLeaf(JavaTokenType.SEMICOLON, ";", null);
int offset = calculateOffset((PsiNewExpression)replace, accessibility, typeRequiresRefinement);
editor.getCaretModel().moveToOffset(offset);
}
}
}
}
private static int calculateOffset(PsiNewExpression expression, CtorAccessibility accessibility, boolean typeRequiresRefinement) {
PsiExpressionList argumentList = expression.getArgumentList();
assert argumentList != null;
if (accessibility == CtorAccessibility.WITH_PARAMETRIC_CTOR || accessibility == CtorAccessibility.NOT_ACCESSIBLE) { // new T(<caret>)
return argumentList.getFirstChild().getTextRange().getEndOffset();
}
else if (typeRequiresRefinement) {
PsiAnonymousClass anonymousClass = expression.getAnonymousClass();
PsiElement lBrace = anonymousClass != null ? anonymousClass.getLBrace() : null;
if (lBrace != null) return lBrace.getTextRange().getEndOffset();
}
return expression.getTextRange().getEndOffset();
}
public enum CtorAccessibility {
NOT_ACCESSIBLE,
WITH_DEFAULT_CTOR,
WITH_PARAMETRIC_CTOR
}
private static CtorAccessibility calcAccessibility(@Nullable PsiClass psiClass, @NotNull PsiElement accessContext) {
if (psiClass == null) return CtorAccessibility.NOT_ACCESSIBLE;
if (psiClass.isEnum()) return CtorAccessibility.NOT_ACCESSIBLE;
if (psiClass.isInterface()) return CtorAccessibility.WITH_DEFAULT_CTOR;
PsiClass containingType = PsiTreeUtil.getParentOfType(accessContext, PsiClass.class);
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(accessContext.getProject());
PsiResolveHelper resolveHelper = psiFacade.getResolveHelper();
PsiMethod[] constructors = psiClass.getConstructors();
if (constructors.length == 0) return CtorAccessibility.WITH_DEFAULT_CTOR;
boolean hasAccessibleCtors = false, hasParametricCtors = false;
for (PsiMethod constructor : constructors) {
if (resolveHelper.isAccessible(constructor, accessContext, containingType)) {
hasAccessibleCtors = true;
int parametersCount = constructor.getParameterList().getParametersCount();
if (parametersCount != 0) hasParametricCtors = true;
}
}
if (!hasAccessibleCtors) return CtorAccessibility.NOT_ACCESSIBLE;
return hasParametricCtors ? CtorAccessibility.WITH_PARAMETRIC_CTOR : CtorAccessibility.WITH_DEFAULT_CTOR;
}
}
@@ -0,0 +1,32 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.CodeInsightServicesUtil;
import com.intellij.codeInsight.template.postfix.util.Aliases;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiExpression;
import org.jetbrains.annotations.NotNull;
@Aliases("!")
public class NotExpressionPostfixTemplate extends ExpressionPostfixTemplateWithChooser {
public NotExpressionPostfixTemplate() {
super("not", "Negates boolean expression", "!expr");
}
@Override
protected void doIt(@NotNull Editor editor, @NotNull PsiExpression expression) {
expression.replace(CodeInsightServicesUtil.invertCondition(expression));
}
@NotNull
@Override
protected Condition<PsiExpression> getTypeCondition() {
return new Condition<PsiExpression>() {
@Override
public boolean value(PsiExpression expression) {
return PostfixTemplatesUtils.isBoolean(expression.getType());
}
};
}
}
@@ -0,0 +1,17 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.Aliases;
import org.jetbrains.annotations.NotNull;
@Aliases(".nn")
public class NotNullCheckPostfixTemplate extends NullCheckPostfixTemplate {
public NotNullCheckPostfixTemplate() {
super("notnull", "Checks expression to be not-null", "if (expr != null)");
}
@NotNull
@Override
protected String getTail() {
return "!= null";
}
}
@@ -0,0 +1,46 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
/**
* @author ignatov
*/
public abstract class NullCheckPostfixTemplate extends PostfixTemplate {
protected NullCheckPostfixTemplate(@NotNull String name, @NotNull String description, @NotNull String example) {
super(name, description, example);
}
@NotNull
abstract String getTail();
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression expr = getTopmostExpression(context);
PsiElement parent = expr != null ? expr.getParent() : null;
return parent instanceof PsiExpressionStatement;
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expr = getTopmostExpression(context);
if (expr == null) return;
Project project = expr.getProject();
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
PsiBinaryExpression condition = (PsiBinaryExpression)factory.createExpressionFromText(expr.getText() + getTail(), context);
PsiElement replace = expr.replace(condition);
assert replace instanceof PsiExpression;
TextRange range = PostfixTemplatesUtils.ifStatement(project, editor, (PsiExpression)replace);
if (range != null) {
editor.getCaretModel().moveToOffset(range.getStartOffset());
}
}
}
@@ -0,0 +1,24 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiParenthesizedExpression;
import org.jetbrains.annotations.NotNull;
public class ParenthesizedExpressionPostfixTemplate extends ExpressionPostfixTemplateWithChooser {
public ParenthesizedExpressionPostfixTemplate() {
super("par", "Parenthesizes expression", "(expression)");
}
@Override
protected void doIt(@NotNull Editor editor, @NotNull PsiExpression expression) {
PsiElementFactory factory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory();
PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)factory.createExpressionFromText("(expr)", expression.getParent());
PsiExpression operand = parenthesizedExpression.getExpression();
assert operand != null;
operand.replace(expression);
expression.replace(parenthesizedExpression);
}
}
@@ -0,0 +1,270 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.completion.CompletionInitializationContext;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.JavaCompletionContributor;
import com.intellij.codeInsight.template.CustomLiveTemplateBase;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
import com.intellij.codeInsight.template.postfix.util.Aliases;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.undo.UndoConstants;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
public class PostfixLiveTemplate extends CustomLiveTemplateBase {
public static final String POSTFIX_TEMPLATE_ID = "POSTFIX_TEMPLATE_ID";
private static final Logger LOG = Logger.getInstance(PostfixLiveTemplate.class);
private final HashMap<String, PostfixTemplate> myTemplates = ContainerUtil.newHashMap();
public PostfixLiveTemplate() {
for (PostfixTemplate template : PostfixTemplate.EP_NAME.getExtensions()) {
register(template.getKey(), template);
Aliases aliases = template.getClass().getAnnotation(Aliases.class);
if (aliases != null) {
for (String key : aliases.value()) {
register(key, template);
}
}
}
}
private void register(@NotNull String key, @NotNull PostfixTemplate template) {
PostfixTemplate registered = myTemplates.put(key, template);
if (registered != null) {
LOG.error("Can't register postfix template. Duplicated key: " + template.getKey());
}
}
@Nullable
@Override
public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
Editor editor = callback.getEditor();
String key = computeTemplateKeyWithoutContextChecking(editor.getDocument().getCharsSequence(), editor.getCaretModel().getOffset());
if (key == null) return null;
return isApplicableTemplate(getTemplateByKey(key), key, callback.getContext().getContainingFile(), editor) ? key : null;
}
@Nullable
public String computeTemplateKeyWithoutContextChecking(@NotNull CharSequence documentContent, int currentOffset) {
int startOffset = currentOffset;
while (startOffset > 0) {
char currentChar = documentContent.charAt(startOffset - 1);
if (!Character.isJavaIdentifierPart(currentChar)) {
if (currentChar != '.' && currentChar != '!') {
return null;
}
startOffset--;
break;
}
startOffset--;
}
return String.valueOf(documentContent.subSequence(startOffset, currentOffset));
}
@Override
public void expand(@NotNull final String key, @NotNull final CustomTemplateCallback callback) {
ApplicationManager.getApplication().assertIsDispatchThread();
final PostfixTemplate template = getTemplateByKey(key);
final Editor editor = callback.getEditor();
final PsiFile file = callback.getContext().getContainingFile();
if (isApplicableTemplate(template, key, file, editor)) {
int currentOffset = editor.getCaretModel().getOffset();
PsiElement newContext = deleteTemplateKey(file, editor.getDocument(), currentOffset, key);
newContext = addSemicolonIfNeeded(editor, editor.getDocument(), newContext, currentOffset - key.length());
expandTemplate(template, editor, newContext);
}
else {
LOG.error("Template not found by key: " + key);
}
}
@Override
public boolean isApplicable(PsiFile file, int offset, boolean wrapping) {
PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
if (wrapping || file == null || settings == null || !settings.isPostfixTemplatesEnabled() ||
PsiUtilCore.getLanguageAtOffset(file, offset) != JavaLanguage.INSTANCE) {
return false;
}
return StringUtil.isNotEmpty(computeTemplateKeyWithoutContextChecking(file.getText(), offset + 1));
}
@Override
public boolean supportsWrapping() {
return false;
}
@Override
public void wrap(@NotNull String selection, @NotNull CustomTemplateCallback callback) {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public String getTitle() {
return "Postfix";
}
@Override
public char getShortcut() {
PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
return settings != null ? (char)settings.getShortcut() : TemplateSettings.TAB_CHAR;
}
@Override
public boolean hasCompletionItem(@NotNull PsiFile file, int offset) {
return true;
}
@Nullable
public PostfixTemplate getTemplateByKey(@NotNull String key) {
return myTemplates.get(key);
}
private static void expandTemplate(@NotNull final PostfixTemplate template,
@NotNull final Editor editor,
@NotNull final PsiElement context) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().executeCommand(context.getProject(), new Runnable() {
public void run() {
template.expand(context, editor);
}
}, "Expand postfix template", POSTFIX_TEMPLATE_ID);
}
});
}
@Contract("null, _, _, _ -> false")
private static boolean isApplicableTemplate(@Nullable PostfixTemplate template, @NotNull String key, @NotNull PsiFile file, @NotNull Editor editor) {
if (template == null || !template.isEnabled()) {
return false;
}
int currentOffset = editor.getCaretModel().getOffset();
int newOffset = currentOffset - key.length();
CharSequence fileContent = editor.getDocument().getCharsSequence();
StringBuilder fileContentWithoutKey = new StringBuilder();
fileContentWithoutKey.append(fileContent.subSequence(0, newOffset));
fileContentWithoutKey.append(fileContent.subSequence(currentOffset, fileContent.length()));
PsiFile copyFile = copyFile(file, fileContentWithoutKey);
Document copyDocument = copyFile.getViewProvider().getDocument();
if (copyDocument == null) {
return false;
}
if (isSemicolonNeeded(copyFile, editor)) {
fileContentWithoutKey.insert(newOffset, ';');
copyFile = copyFile(file, fileContentWithoutKey);
copyDocument = copyFile.getViewProvider().getDocument();
if (copyDocument == null) {
return false;
}
}
PsiElement context = CustomTemplateCallback.getContext(copyFile, newOffset > 0 ? newOffset - 1 : newOffset);
return template.isApplicable(context, copyDocument, newOffset);
}
@NotNull
private static PsiFile copyFile(@NotNull PsiFile file, @NotNull StringBuilder fileContentWithoutKey) {
final PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(file.getProject());
PsiFile copy = psiFileFactory.createFileFromText(file.getName(), file.getFileType(), fileContentWithoutKey);
VirtualFile vFile = copy.getVirtualFile();
if (vFile != null) {
vFile.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
}
return copy;
}
@NotNull
private static PsiElement deleteTemplateKey(@NotNull final PsiFile file,
@NotNull final Document document,
final int currentOffset,
@NotNull final String key) {
ApplicationManager.getApplication().assertIsDispatchThread();
final int startOffset = currentOffset - key.length();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
public void run() {
document.deleteString(startOffset, currentOffset);
PsiDocumentManager.getInstance(file.getProject()).commitDocument(document);
}
});
}
});
return CustomTemplateCallback.getContext(file, startOffset > 0 ? startOffset - 1 : startOffset);
}
@NotNull
private static PsiElement addSemicolonIfNeeded(@NotNull final Editor editor,
@NotNull final Document document,
@NotNull final PsiElement context,
final int offset) {
ApplicationManager.getApplication().assertIsDispatchThread();
final Ref<PsiElement> newContext = Ref.create(context);
final PsiFile file = context.getContainingFile();
if (isSemicolonNeeded(file, editor)) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
public void run() {
document.insertString(offset, ";");
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
newContext.set(CustomTemplateCallback.getContext(file, offset - 1));
}
});
}
});
}
return newContext.get();
}
private static boolean isSemicolonNeeded(@NotNull PsiFile file, @NotNull Editor editor) {
CompletionInitializationContext initializationContext = new CompletionInitializationContext(editor, file, CompletionType.BASIC);
new JavaCompletionContributor().beforeCompletion(initializationContext);
return StringUtil.endsWithChar(initializationContext.getDummyIdentifier(), ';');
}
}
@@ -0,0 +1,81 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class PostfixTemplate {
@NotNull private final String myPresentableName;
@NotNull private final String myKey;
@NotNull private final String myDescription;
@NotNull private final String myExample;
@NotNull
public static final ExtensionPointName<PostfixTemplate> EP_NAME = ExtensionPointName.create("com.intellij.postfixTemplate");
protected PostfixTemplate(@NotNull String name, @NotNull String description, @NotNull String example) {
this(name, "." + name, description, example);
}
protected PostfixTemplate(@NotNull String name, @NotNull String key, @NotNull String description, @NotNull String example) {
myPresentableName = name;
myKey = key;
myDescription = description;
myExample = example;
}
@NotNull
public final String getKey() {
return myKey;
}
@NotNull
public String getPresentableName() {
return myPresentableName;
}
@NotNull
public String getDescription() {
return myDescription;
}
@NotNull
public String getExample() {
return myExample;
}
public boolean isEnabled() {
final PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
return settings != null && settings.isPostfixTemplatesEnabled() && settings.isTemplateEnabled(this);
}
@Nullable
public static PsiExpression getTopmostExpression(PsiElement context) {
return PsiTreeUtil.getTopmostParentOfType(context, PsiExpression.class);
}
public abstract boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset);
public abstract void expand(@NotNull PsiElement context, @NotNull Editor editor);
}
@@ -0,0 +1,30 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
public class ReturnStatementPostfixTemplate extends PostfixTemplate {
public ReturnStatementPostfixTemplate() {
super("return", "Returns value from containing method", "return expr;");
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression expr = getTopmostExpression(context);
if (expr == null || !(expr.getParent() instanceof PsiExpressionStatement)) return false;
PsiType type = expr.getType();
return type != null && !PsiType.VOID.equals(type);
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expr = getTopmostExpression(context);
PsiElement parent = expr != null ? expr.getParent() : null;
if (!(parent instanceof PsiExpressionStatement)) return;
PsiElementFactory factory = JavaPsiFacade.getInstance(expr.getProject()).getElementFactory();
PsiReturnStatement returnStatement = (PsiReturnStatement)factory.createStatementFromText("return " + expr.getText() + ";", parent);
parent.replace(returnStatement);
}
}
@@ -0,0 +1,37 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
/**
* @author ignatov
*/
public abstract class StatementPostfixTemplateBase extends PostfixTemplate {
protected StatementPostfixTemplateBase(String name, String description, String example) {
super(name, description, example);
}
protected void surroundWith(PsiElement context, Editor editor, String text) {
PsiExpression expr = getTopmostExpression(context);
PsiElement parent = expr != null ? expr.getParent() : null;
if (!(parent instanceof PsiExpressionStatement)) return;
Project project = context.getProject();
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
PsiElement statement = codeStyleManager.reformat(factory.createStatementFromText(text + " (" + expr.getText() + ") {\nst;\n}", context));
statement = parent.replace(statement);
//noinspection ConstantConditions
PsiCodeBlock block = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(PsiTreeUtil.getChildOfType(statement, PsiCodeBlock.class));
TextRange range = block.getStatements()[0].getTextRange();
editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset());
editor.getCaretModel().moveToOffset(range.getStartOffset());
}
}
@@ -0,0 +1,47 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SwitchStatementPostfixTemplate extends StatementPostfixTemplateBase {
public SwitchStatementPostfixTemplate() {
super("switch", "Produces switch over integral/enum/string values", "switch (expr)");
}
private static boolean isSwitchCompatibleType(@Nullable PsiType type, @NotNull PsiElement context) {
if (type == null) return false;
if (PsiType.INT.isAssignableFrom(type)) return true;
if (type instanceof PsiClassType) {
PsiClass psiClass = ((PsiClassType)type).resolve();
if (psiClass != null && psiClass.isEnum()) return true;
}
if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
if (ApplicationManager.getApplication().isUnitTestMode()) return true; // todo: mock jdk 6 and 7
PsiFile containingFile = context.getContainingFile();
if (containingFile instanceof PsiJavaFile) {
LanguageLevel level = ((PsiJavaFile)containingFile).getLanguageLevel();
if (level.isAtLeast(LanguageLevel.JDK_1_7)) return true;
}
}
return false;
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression expr = getTopmostExpression(context);
return expr != null && expr.getParent() instanceof PsiExpressionStatement && isSwitchCompatibleType(expr.getType(), context);
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
surroundWith(context, editor, "switch");
}
}
@@ -0,0 +1,25 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
public class SynchronizedStatementPostfixTemplate extends StatementPostfixTemplateBase {
public SynchronizedStatementPostfixTemplate() {
super("synchronized", "Produces synchronization statement", "synchronized (expr)");
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression expression = getTopmostExpression(context);
PsiElement parent = expression != null ? expression.getParent() : null;
PsiType type = expression != null ? expression.getType() : null;
return parent instanceof PsiExpressionStatement && type != null && !(type instanceof PsiPrimitiveType);
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
surroundWith(context, editor, "synchronized");
}
}
@@ -0,0 +1,27 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.postfix.util.PostfixTemplatesUtils;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionStatement;
import org.jetbrains.annotations.NotNull;
public class ThrowExceptionPostfixTemplate extends PostfixTemplate {
public ThrowExceptionPostfixTemplate() {
super("throw", "Throws expression of 'Throwable' type", "throw expr;");
}
@Override
public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
PsiExpression expr = getTopmostExpression(context);
PsiElement parent = expr != null ? expr.getParent() : null;
return parent instanceof PsiExpressionStatement;
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PostfixTemplatesUtils.createSimpleStatement(context, editor, "throw");
}
}
@@ -0,0 +1,31 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
public class WhileStatementPostfixTemplate extends BooleanPostfixTemplate {
public WhileStatementPostfixTemplate() {
super("while", "Iterating while boolean statement is 'true'", "while (expr)");
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expression = getTopmostExpression(context);
assert expression != null;
PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject());
PsiWhileStatement whileStatement = (PsiWhileStatement)factory.createStatementFromText("while(expr)", context);
PsiExpression condition = whileStatement.getCondition();
assert condition != null;
condition.replace(expression);
PsiElement replacedWhileStatement = expression.replace(whileStatement);
if (replacedWhileStatement instanceof PsiWhileStatement) {
PsiJavaToken parenth = ((PsiWhileStatement)replacedWhileStatement).getRParenth();
if (parenth != null) {
editor.getCaretModel().moveToOffset(parenth.getTextRange().getEndOffset());
}
}
}
}
@@ -0,0 +1,15 @@
package com.intellij.codeInsight.template.postfix.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author ignatov
*/
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Aliases {
String[] value();
}
@@ -0,0 +1,102 @@
/*
* Copyright 2000-2013 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.codeInsight.template.postfix.util;
import com.intellij.codeInsight.generation.surroundWith.JavaExpressionSurrounder;
import com.intellij.codeInsight.generation.surroundWith.JavaWithIfExpressionSurrounder;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class PostfixTemplatesUtils {
private PostfixTemplatesUtils() {
}
public static void showErrorHint(Project project, Editor editor) {
CommonRefactoringUtil.showErrorHint(project, editor, "Can't expand postfix template", "Can't expand postfix template", "");
}
public static void createSimpleStatement(@NotNull PsiElement context, @NotNull Editor editor, @NotNull String text) {
PsiExpression expr = PostfixTemplate.getTopmostExpression(context);
PsiElement parent = expr != null ? expr.getParent() : null;
assert parent instanceof PsiStatement;
PsiElementFactory factory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
PsiStatement assertStatement = factory.createStatementFromText(text + " " + expr.getText() + ";", parent);
PsiElement replace = parent.replace(assertStatement);
editor.getCaretModel().moveToOffset(replace.getTextRange().getEndOffset());
}
@Contract("null -> false")
public static boolean isIterable(@Nullable PsiType type) {
return type != null && InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_ITERABLE);
}
@Contract("null -> false")
public static boolean isArray(@Nullable PsiType type) {
return type != null && type instanceof PsiArrayType;
}
@Contract("null -> false")
public static boolean isBoolean(@Nullable PsiType type) {
return type != null && (PsiType.BOOLEAN.equals(type) || PsiType.BOOLEAN.equals(PsiPrimitiveType.getUnboxedType(type)));
}
@Contract("null -> false")
public static boolean isNumber(@Nullable PsiType type) {
if (type == null) {
return false;
}
if (PsiType.INT.equals(type) || PsiType.BYTE.equals(type) || PsiType.LONG.equals(type)) {
return true;
}
PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
return PsiType.INT.equals(unboxedType) || PsiType.BYTE.equals(unboxedType) || PsiType.LONG.equals(unboxedType);
}
@Nullable
public static TextRange ifStatement(@NotNull Project project, @NotNull Editor editor, @NotNull PsiExpression expr) {
JavaExpressionSurrounder surrounder = new JavaWithIfExpressionSurrounder();
PsiElement[] elements = {expr};
if (surrounder.isApplicable(elements)) {
return surrounder.surroundElements(project, editor, elements);
}
else {
showErrorHint(project, editor);
}
return null;
}
@Nullable
public static TextRange apply(@NotNull JavaExpressionSurrounder surrounder, @NotNull Project project, @NotNull Editor editor, @NotNull PsiExpression expr) {
PsiElement[] elements = {expr};
if (surrounder.isApplicable(elements)) {
return surrounder.surroundElements(project, editor, elements);
}
else {
showErrorHint(project, editor);
}
return null;
}
}
@@ -107,6 +107,7 @@ public class JavaPsiImplementationHelperImpl extends JavaPsiImplementationHelper
return original != null ? original : psiClass;
}
@NotNull
@Override
public PsiElement getClsFileNavigationElement(PsiJavaFile clsFile) {
String packageName = clsFile.getPackageName();
@@ -175,7 +175,13 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
final Editor editor,
final int offset,
boolean acceptVoid) {
Document document = editor.getDocument();
return collectExpressions(file, editor.getDocument(), offset, acceptVoid);
}
public static List<PsiExpression> collectExpressions(final PsiFile file,
final Document document,
final int offset,
boolean acceptVoid) {
CharSequence text = document.getCharsSequence();
int correctedOffset = offset;
int textLength = document.getTextLength();
@@ -43,7 +43,7 @@ public class PackageGroupingRule extends DirectoryGroupingRule {
}
@Override
protected UsageGroup getGroupForFile(final VirtualFile dir) {
protected UsageGroup getGroupForFile(@NotNull final VirtualFile dir) {
PsiDirectory psiDirectory = PsiManager.getInstance(myProject).findDirectory(dir);
if (psiDirectory != null) {
PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(psiDirectory);
@@ -22,7 +22,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.LowMemoryWatcher;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -52,7 +51,7 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.BaseExternalAnnotationsManager");
@NotNull private static final List<PsiFile> NULL_LIST = new ArrayList<PsiFile>(0);
@NotNull
private final ConcurrentMap<String, List<PsiFile>> myExternalAnnotations = new ConcurrentSoftValueHashMap<String, List<PsiFile>>(10, 0.75f, 2);
private final ConcurrentMap<VirtualFile, List<PsiFile>> myExternalAnnotations = new ConcurrentSoftValueHashMap<VirtualFile, List<PsiFile>>(10, 0.75f, 2);
protected final PsiManager myPsiManager;
@SuppressWarnings("UnusedDeclaration")
@@ -72,13 +71,6 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
return PsiFormatUtil.getExternalName(listOwner, showParamName, Integer.MAX_VALUE);
}
@Nullable
private static String getFQN(@NotNull String packageName, @NotNull PsiFile psiFile) {
VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile == null) return null;
return StringUtil.getQualifiedName(packageName, virtualFile.getNameWithoutExtension());
}
protected abstract boolean hasAnyAnnotationsRoots();
@Override
@@ -230,9 +222,9 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
final PsiJavaFile javaFile = (PsiJavaFile)containingFile;
final String packageName = javaFile.getPackageName();
final VirtualFile virtualFile = containingFile.getVirtualFile();
String fqn = getFQN(packageName, containingFile);
if (fqn == null) return null;
final List<PsiFile> files = myExternalAnnotations.get(fqn);
if (virtualFile == null) return null;
final List<PsiFile> files = myExternalAnnotations.get(virtualFile);
if (files == NULL_LIST) return null;
if (files != null) {
boolean allValid = true;
@@ -258,7 +250,7 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
}
List<PsiFile> result;
if (possibleAnnotationsXmls.isEmpty()) {
myExternalAnnotations.put(fqn, NULL_LIST);
myExternalAnnotations.put(virtualFile, NULL_LIST);
result = null;
}
else {
@@ -276,7 +268,7 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
}
});
myExternalAnnotations.put(fqn, result);
myExternalAnnotations.put(virtualFile, result);
}
return result;
}
@@ -344,9 +336,9 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
}
protected void cacheExternalAnnotations(@NotNull String packageName, @NotNull PsiFile fromFile, @NotNull List<PsiFile> annotationFiles) {
String fqn = getFQN(packageName, fromFile);
if (fqn != null) {
myExternalAnnotations.put(fqn, annotationFiles);
VirtualFile virtualFile = fromFile.getVirtualFile();
if (virtualFile != null) {
myExternalAnnotations.put(virtualFile, annotationFiles);
}
}
@@ -27,6 +27,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
@@ -58,18 +59,18 @@ import java.util.regex.Pattern;
public class JavaDocInfoGenerator {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.javadoc.JavaDocInfoGenerator");
private static final @NonNls Pattern ourNotDot = Pattern.compile("[^.]");
private static final @NonNls Pattern ourWhitespaces = Pattern.compile("[ \\n\\r\\t]+");
@NonNls private static final Pattern ourNotDot = Pattern.compile("[^.]");
@NonNls private static final Pattern ourWhitespaces = Pattern.compile("[ \\n\\r\\t]+");
private static final @NonNls String THROWS_KEYWORD = "throws";
private static final @NonNls String BR_TAG = "<br>";
private static final @NonNls String LINK_TAG = "link";
private static final @NonNls String LITERAL_TAG = "literal";
private static final @NonNls String CODE_TAG = "code";
private static final @NonNls String LINKPLAIN_TAG = "linkplain";
private static final @NonNls String INHERITDOC_TAG = "inheritDoc";
private static final @NonNls String DOCROOT_TAG = "docRoot";
private static final @NonNls String VALUE_TAG = "value";
@NonNls private static final String THROWS_KEYWORD = "throws";
@NonNls private static final String BR_TAG = "<br>";
@NonNls private static final String LINK_TAG = "link";
@NonNls private static final String LITERAL_TAG = "literal";
@NonNls private static final String CODE_TAG = "code";
@NonNls private static final String LINKPLAIN_TAG = "linkplain";
@NonNls private static final String INHERITDOC_TAG = "inheritDoc";
@NonNls private static final String DOCROOT_TAG = "docRoot";
@NonNls private static final String VALUE_TAG = "value";
private final Project myProject;
private final PsiElement myElement;
@@ -204,7 +205,7 @@ public class JavaDocInfoGenerator {
@Nullable
private static String fixupDoc(@NotNull final StringBuilder buffer) {
String text = buffer.toString();
if (text.length() == 0) {
if (text.isEmpty()) {
return null;
}
if (LOG.isDebugEnabled()) {
@@ -253,14 +254,14 @@ public class JavaDocInfoGenerator {
return null;
if (docURLs != null) {
StringBuilder errorsSection = new StringBuilder("<p id=\"error\">Following external urls were checked:<br>&nbsp;&nbsp;&nbsp;<i>");
errorsSection.append(StringUtil.join(docURLs, "</i><br>&nbsp;&nbsp;&nbsp;<i>"));
errorsSection.append("</i><br>The documentation for this element is not found. Please add all the needed paths to API docs in ");
errorsSection.append("<a href=\"open://Project Settings\">Project Settings.</a></p>");
if (buffer.length() == 0) {
buffer.append("<html><body></body></html>");
}
buffer.insert(buffer.indexOf("<body>"), errorsSection.toString());
String errorSection = "<p id=\"error\">Following external urls were checked:<br>&nbsp;&nbsp;&nbsp;<i>" +
StringUtil.join(docURLs, "</i><br>&nbsp;&nbsp;&nbsp;<i>") +
"</i><br>The documentation for this element is not found. Please add all the needed paths to API docs in " +
"<a href=\"open://Project Settings\">Project Settings.</a></p>";
buffer.insert(buffer.indexOf("<body>"), errorSection);
}
return fixupDoc(buffer);
}
@@ -274,7 +275,7 @@ public class JavaDocInfoGenerator {
PsiFile file = aClass.getContainingFile();
if (file instanceof PsiJavaFile) {
String packageName = ((PsiJavaFile)file).getPackageName();
if (packageName.length() > 0) {
if (!packageName.isEmpty()) {
buffer.append("<small><b>");
buffer.append(packageName);
buffer.append("</b></small>");
@@ -285,7 +286,7 @@ public class JavaDocInfoGenerator {
buffer.append("<PRE>");
generateAnnotations(buffer, aClass);
String modifiers = PsiFormatUtil.formatModifiers(aClass, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
if (modifiers.length() > 0) {
if (!modifiers.isEmpty()) {
buffer.append(modifiers);
buffer.append(" ");
}
@@ -445,7 +446,7 @@ public class JavaDocInfoGenerator {
buffer.append("<PRE>");
generateAnnotations(buffer, field);
String modifiers = PsiFormatUtil.formatModifiers(field, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
if (modifiers.length() > 0) {
if (!modifiers.isEmpty()) {
buffer.append(modifiers);
buffer.append(" ");
}
@@ -487,7 +488,7 @@ public class JavaDocInfoGenerator {
buffer.append("<PRE>");
String modifiers = PsiFormatUtil.formatModifiers(variable, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
if (modifiers.length() > 0) {
if (!modifiers.isEmpty()) {
buffer.append(modifiers);
buffer.append(" ");
}
@@ -558,7 +559,7 @@ public class JavaDocInfoGenerator {
String htmlText = packageHtmlFile.getText();
try {
final Document document = JDOMUtil.loadDocument(new ByteArrayInputStream(htmlText.getBytes()));
final Document document = JDOMUtil.loadDocument(new ByteArrayInputStream(htmlText.getBytes(CharsetToolkit.UTF8_CHARSET)));
final Element rootTag = document.getRootElement();
if (rootTag != null) {
final Element subTag = rootTag.getChild("body");
@@ -616,7 +617,7 @@ public class JavaDocInfoGenerator {
}
}
private static void generateAnnotations(@NonNls StringBuilder buffer, PsiModifierListOwner owner) {
private static void generateAnnotations(@NonNls @NotNull StringBuilder buffer, @NotNull PsiModifierListOwner owner) {
final PsiModifierList ownerModifierList = owner.getModifierList();
if (ownerModifierList == null) return;
PsiAnnotation[] annotations = ownerModifierList.getAnnotations();
@@ -638,8 +639,8 @@ public class JavaDocInfoGenerator {
generateType(buffer, type, owner);
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length > 0) {
boolean first = true;
buffer.append("(");
boolean first = true;
for (PsiNameValuePair pair : attributes) {
if (!first) buffer.append("&nbsp;");
first = false;
@@ -672,7 +673,7 @@ public class JavaDocInfoGenerator {
buffer.append("<PRE>");
String modifiers = PsiFormatUtil.formatModifiers(parameter, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
if (modifiers.length() > 0) {
if (!modifiers.isEmpty()) {
buffer.append(modifiers);
buffer.append(" ");
}
@@ -721,10 +722,10 @@ public class JavaDocInfoGenerator {
}
buffer.append("<PRE>");
int indent = 0;
generateAnnotations(buffer, method);
String modifiers = PsiFormatUtil.formatModifiers(method, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
if (modifiers.length() > 0) {
int indent = 0;
if (!modifiers.isEmpty()) {
buffer.append(modifiers);
buffer.append("&nbsp;");
indent += modifiers.length() + 1;
@@ -732,7 +733,7 @@ public class JavaDocInfoGenerator {
final String typeParamsString = generateTypeParameters(method);
indent += typeParamsString.length();
if (typeParamsString.length() > 0) {
if (!typeParamsString.isEmpty()) {
buffer.append(typeParamsString);
buffer.append("&nbsp;");
indent++;
@@ -923,7 +924,7 @@ public class JavaDocInfoGenerator {
String text = description.getText();
if (text != null) {
if (ourWhitespaces.matcher(text).replaceAll("").length() != 0) {
if (!ourWhitespaces.matcher(text).replaceAll("").isEmpty()) {
return false;
}
}
@@ -993,7 +994,7 @@ public class JavaDocInfoGenerator {
}
private String getDocRoot() {
PsiClass aClass = null;
PsiClass aClass;
if (myElement instanceof PsiClass) {
aClass = (PsiClass)myElement;
@@ -1033,10 +1034,7 @@ public class JavaDocInfoGenerator {
if (element instanceof PsiInlineDocTag) {
PsiInlineDocTag tag = (PsiInlineDocTag)element;
final String tagName = tag.getName();
if (tagName == null) {
buffer.append(element.getText());
}
else if (tagName.equals(LINK_TAG)) {
if (tagName.equals(LINK_TAG)) {
generateLinkValue(tag, buffer, false);
}
else if (tagName.equals(LITERAL_TAG)) {
@@ -1091,14 +1089,14 @@ public class JavaDocInfoGenerator {
buffer.append(text);
}
private void generateLinkValue(PsiInlineDocTag tag, StringBuilder buffer, boolean plainLink) {
private static void generateLinkValue(PsiInlineDocTag tag, StringBuilder buffer, boolean plainLink) {
PsiElement[] tagElements = tag.getDataElements();
String text = createLinkText(tagElements);
if (text.length() > 0) {
if (!text.isEmpty()) {
int index = JavaDocUtil.extractReference(text);
String refText = text.substring(0, index).trim();
String label = text.substring(index).trim();
if (label.length() == 0) {
if (label.isEmpty()) {
label = null;
}
generateLink(buffer, refText, label, tagElements[0], plainLink);
@@ -1108,7 +1106,7 @@ public class JavaDocInfoGenerator {
private void generateValueValue(final PsiInlineDocTag tag, final StringBuilder buffer, final PsiElement element) {
String text = createLinkText(tag.getDataElements());
PsiField valueField = null;
if (text.length() == 0) {
if (text.isEmpty()) {
if (myElement instanceof PsiField) valueField = (PsiField) myElement;
}
else {
@@ -1125,7 +1123,7 @@ public class JavaDocInfoGenerator {
}
if (value != null) {
buffer.append(value.toString());
buffer.append(value);
}
else {
buffer.append(element.getText());
@@ -1178,7 +1176,7 @@ public class JavaDocInfoGenerator {
}
@SuppressWarnings({"HardCodedStringLiteral"})
private void generateSeeAlsoSection(StringBuilder buffer, PsiDocComment comment) {
private static void generateSeeAlsoSection(StringBuilder buffer, PsiDocComment comment) {
PsiDocTag[] tags = comment.findTagsByName("see");
if (tags.length > 0) {
buffer.append("<DD><DL>");
@@ -1200,7 +1198,7 @@ public class JavaDocInfoGenerator {
int index = JavaDocUtil.extractReference(text);
String refText = text.substring(0, index).trim();
String label = text.substring(index).trim();
if (label.length() == 0) {
if (label.isEmpty()) {
label = null;
}
generateLink(buffer, refText, label, comment, false);
@@ -1231,7 +1229,7 @@ public class JavaDocInfoGenerator {
}
}
if (collectedTags.size() > 0) {
if (!collectedTags.isEmpty()) {
buffer.append("<DD><DL>");
buffer.append("<DT><b>").append(CodeInsightBundle.message("javadoc.parameters")).append("</b>");
for (Pair<PsiDocTag, InheritDocProvider<PsiDocTag>> tag : collectedTags) {
@@ -1261,7 +1259,7 @@ public class JavaDocInfoGenerator {
}
private void generateTypeParametersSection(final StringBuilder buffer, final LinkedList<Pair<PsiDocTag, InheritDocProvider<PsiDocTag>>> collectedTags) {
if (collectedTags.size() > 0) {
if (!collectedTags.isEmpty()) {
buffer.append("<DD><DL>");
buffer.append("<DT><b>").append(CodeInsightBundle.message("javadoc.type.parameters")).append("</b>");
for (Pair<PsiDocTag, InheritDocProvider<PsiDocTag>> tag : collectedTags) {
@@ -1347,7 +1345,7 @@ public class JavaDocInfoGenerator {
});
if (pair == null && myElement instanceof PsiMethod) {
pair = findInheritDocTag(((PsiMethod)myElement), new ReturnTagLocator());
pair = findInheritDocTag((PsiMethod)myElement, new ReturnTagLocator());
}
if (pair != null) {
@@ -1451,7 +1449,7 @@ public class JavaDocInfoGenerator {
}
}
if (collectedTags.size() > 0) {
if (!collectedTags.isEmpty()) {
buffer.append("<DD><DL>");
buffer.append("<DT><b>").append(CodeInsightBundle.message("javadoc.throws")).append("</b>");
for (Pair<PsiDocTag, InheritDocProvider<PsiDocTag>> tag : collectedTags) {
@@ -1463,7 +1461,7 @@ public class JavaDocInfoGenerator {
String refText = text.substring(0, index).trim();
generateLink(buffer, refText, null, method, false);
String rest = text.substring(index);
if (rest.length() > 0 || elements.length > 1) buffer.append(" - ");
if (!rest.isEmpty() || elements.length > 1) buffer.append(" - ");
buffer.append(rest);
generateValue(buffer, elements, 1, mapProvider(tag.second, true));
}
@@ -1472,7 +1470,7 @@ public class JavaDocInfoGenerator {
}
@SuppressWarnings({"HardCodedStringLiteral"})
private void generateSuperMethodsSection(StringBuilder buffer, PsiMethod method, boolean overrides) {
private static void generateSuperMethodsSection(StringBuilder buffer, PsiMethod method, boolean overrides) {
PsiClass parentClass = method.getContainingClass();
if (parentClass == null) return;
if (parentClass.isInterface() && !overrides) return;
@@ -1571,7 +1569,7 @@ public class JavaDocInfoGenerator {
if (type instanceof PsiArrayType) {
int rest = generateType(buffer, ((PsiArrayType)type).getComponentType(), context, generateLink);
if ((type instanceof PsiEllipsisType)) {
if (type instanceof PsiEllipsisType) {
buffer.append("...");
return rest + 3;
}
@@ -1586,7 +1584,7 @@ public class JavaDocInfoGenerator {
}
if (type instanceof PsiWildcardType){
PsiWildcardType wt = ((PsiWildcardType)type);
PsiWildcardType wt = (PsiWildcardType)type;
buffer.append("?");
@@ -1631,11 +1629,11 @@ public class JavaDocInfoGenerator {
if (psiClass.hasTypeParameters()) {
StringBuilder subst = new StringBuilder();
boolean goodSubst = true;
PsiTypeParameter[] params = psiClass.getTypeParameters();
subst.append("&lt;");
boolean goodSubst = true;
for (int i = 0; i < params.length; i++) {
PsiType t = psiSubst.substitute(params[i]);
@@ -1669,7 +1667,6 @@ public class JavaDocInfoGenerator {
return text.length();
}
else {
int length = 0;
final String separator = type instanceof PsiDisjunctionType ? " | " : " & ";
final List<PsiType> componentTypes;
if (type instanceof PsiIntersectionType) {
@@ -1678,6 +1675,7 @@ public class JavaDocInfoGenerator {
else {
componentTypes = ((PsiDisjunctionType)type).getDisjunctions();
}
int length = 0;
for (PsiType psiType : componentTypes) {
if (length > 0) {
buffer.append(separator);
@@ -1693,7 +1691,7 @@ public class JavaDocInfoGenerator {
}
@SuppressWarnings({"HardCodedStringLiteral"})
private String generateTypeParameters(PsiTypeParameterListOwner owner) {
private static String generateTypeParameters(PsiTypeParameterListOwner owner) {
if (owner.hasTypeParameters()) {
PsiTypeParameter[] parms = owner.getTypeParameters();
@@ -1765,15 +1763,14 @@ public class JavaDocInfoGenerator {
}
@Nullable
private <T> PsiMethod findMethodInSuperClass(PsiMethod method, PsiClass aSuper) {
PsiMethod overriden = null;
private static PsiMethod findMethodInSuperClass(PsiMethod method, PsiClass aSuper) {
for (PsiMethod superMethod : method.findDeepestSuperMethods()) {
overriden = aSuper.findMethodBySignature(superMethod, false);
PsiMethod overriden = aSuper.findMethodBySignature(superMethod, false);
if (overriden != null) {
return overriden;
}
}
return overriden;
return null;
}
@Nullable private <T> Pair<T, InheritDocProvider<T>> searchDocTagInSupers(PsiClassType[] supers,
@@ -31,6 +31,7 @@ public class CoreJavaPsiImplementationHelper extends JavaPsiImplementationHelper
return psiClass;
}
@NotNull
@Override
public PsiElement getClsFileNavigationElement(PsiJavaFile clsFile) {
return clsFile;
@@ -34,6 +34,7 @@ public abstract class JavaPsiImplementationHelper {
public abstract PsiClass getOriginalClass(PsiClass psiClass);
@NotNull
public abstract PsiElement getClsFileNavigationElement(PsiJavaFile clsFile);
/**
@@ -27,6 +27,7 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.progress.NonCancelableSection;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
@@ -44,12 +45,15 @@ import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.stubs.*;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiUtil;
import com.intellij.reference.SoftReference;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
@@ -263,6 +267,21 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub>
@Override
@NotNull
public PsiElement getNavigationElement() {
return CachedValuesManager.getCachedValue(this, new CachedValueProvider<PsiElement>() {
@Nullable
@Override
public Result<PsiElement> compute() {
PsiElement target = calcNavigationElement();
return Result.create(target,
ClsFileImpl.this,
target.getContainingFile(),
FileIndexFacade.getInstance(getProject()).getRootModificationTracker());
}
});
}
@NotNull
private PsiElement calcNavigationElement() {
for (ClsCustomNavigationPolicy customNavigationPolicy : Extensions.getExtensions(ClsCustomNavigationPolicy.EP_NAME)) {
if (customNavigationPolicy instanceof ClsCustomNavigationPolicyEx) {
PsiFile navigationElement = ((ClsCustomNavigationPolicyEx)customNavigationPolicy).getFileNavigationElement(this);
@@ -18,6 +18,7 @@ package com.intellij.psi.impl.compiled;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.AtomicNotNullLazyValue;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.text.StringUtil;
@@ -34,9 +35,7 @@ import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.*;
import com.intellij.ui.RowIcon;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
@@ -280,6 +279,20 @@ public class ClsMethodImpl extends ClsMemberImpl<PsiMethodStub> implements PsiAn
@Nullable
public PsiMethod getSourceMirrorMethod() {
return CachedValuesManager.getCachedValue(this, new CachedValueProvider<PsiMethod>() {
@Nullable
@Override
public Result<PsiMethod> compute() {
return Result.create(calcSourceMirrorMethod(),
getContainingFile(),
getContainingFile().getNavigationElement(),
FileIndexFacade.getInstance(getProject()).getRootModificationTracker());
}
});
}
@Nullable
private PsiMethod calcSourceMirrorMethod() {
PsiClass sourceClassMirror = ((ClsClassImpl)getParent()).getSourceMirrorClass();
if (sourceClassMirror == null) return null;
for (PsiMethod sourceMethod : sourceClassMirror.findMethodsByName(getName(), false)) {
@@ -84,6 +84,9 @@ public class FunctionalInterfaceParameterizationUtil {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiClass.getProject());
final PsiParameter[] targetMethodParams = interfaceMethod.getParameterList().getParameters();
if (targetMethodParams.length != lambdaParams.length) {
return null;
}
for (int i = 0; i < targetMethodParams.length; i++) {
if (resolve) {
session.addConstraint(new TypeEqualityConstraint(lambdaParams[i].getType(), targetMethodParams[i].getType()));
@@ -0,0 +1,8 @@
// "Assert 'container != null'" "true"
class A{
void test(){
Integer container = null;
assert container != null;
for (int i = 0, limit = container.intValue(); i < limit; i++){}
}
}
@@ -0,0 +1,7 @@
// "Assert 'container != null'" "true"
class A{
void test(){
Integer container = null;
for (int i = 0, limit = con<caret>tainer.intValue(); i < limit; i++){}
}
}
@@ -0,0 +1,6 @@
public class Foo {
void m(Object o) {
Foo foo = new Foo() {
};<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m(Object o) {
new Foo() { }.<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
int foo = 2 + 2;<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
2 + 2.<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
Foo foo = new Foo();<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
Foo.<caret>
}
}
@@ -0,0 +1,6 @@
public class Foo {
void m() {
unresolved.var
<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
unresolved.<caret>
}
}
@@ -0,0 +1,7 @@
public class Foo {
Foo m() {
Foo foo = m().m();
foo<caret>.m();
return null;
}
}
@@ -0,0 +1,6 @@
public class Foo {
Foo m() {
m().m().<caret>.m();
return null;
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
boolean foo = true && false;<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
true && false.<caret>
}
}
@@ -0,0 +1,6 @@
public class Foo {
void m(boolean b) {
boolean foo = b && false;
m(foo<caret>);
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m(boolean b) {
m(b && false.<caret>);
}
}
@@ -0,0 +1,5 @@
public class Foo<T> {
void m() {
Foo<Foo> foo = new Foo<Foo>();<caret>
}
}
@@ -0,0 +1,5 @@
public class Foo<T> {
void m() {
Foo<Foo>.<caret>;
}
}
@@ -0,0 +1,8 @@
public class Foo {
Foo f;
Foo m() {
Foo foo = m().m().f;<caret>
m();
return null;
}
}
@@ -0,0 +1,7 @@
public class Foo {
Foo f;
Foo m() {
m().m().f.<caret>m();
return null;
}
}
@@ -0,0 +1,6 @@
public class Foo {
void m() {
int foo = 1;
foo<caret> + 2 /* comment */; // comment2
}
}
@@ -0,0 +1,5 @@
public class Foo {
void m() {
1.<caret> + 2 /* comment */; // comment2
}
}
@@ -0,0 +1,8 @@
public class Foo {
Foo f;
Foo m() {
Foo foo = m().m().f;<caret>
blah();
return null;
}
}
@@ -0,0 +1,7 @@
public class Foo {
Foo f;
Foo m() {
m().m().f.v<caret>blah();
return null;
}
}

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