Remove experimental CodeStyleBean API

This commit is contained in:
Rustam Vishnyakov
2018-12-04 16:43:38 +03:00
parent c68207ac24
commit e05941f3d4
5 changed files with 0 additions and 652 deletions
@@ -1,84 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.application.options;
import com.intellij.formatting.WrapType;
import com.intellij.lang.Language;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
/**
* Wraps language code style options defined in {@code CommonCodeStyleSettings} and {@code CustomCodeStyleSettings} with getter/setter
* methods for external serialization.
*
* @see CommonCodeStyleSettings
* @see CustomCodeStyleSettings
*/
@SuppressWarnings("unused")
@ApiStatus.Experimental
public abstract class CodeStyleBean implements Serializable {
private @NotNull CodeStyleSettings myRootSettings;
public CodeStyleBean() {
myRootSettings = new CodeStyleSettings();
}
public void setRootSettings(@NotNull CodeStyleSettings settings) {
myRootSettings = settings;
}
@NotNull
protected abstract Language getLanguage();
public int getRightMargin() {
return myRootSettings.getRightMargin(getLanguage());
}
public void setRightMargin(int rightMargin) {
myRootSettings.setRightMargin(getLanguage(), rightMargin);
}
@NotNull
public CommonCodeStyleSettings.WrapOnTyping getWrapOnTyping() {
for (CommonCodeStyleSettings.WrapOnTyping c : CommonCodeStyleSettings.WrapOnTyping.values()) {
if (c.intValue == getCommonSettings().WRAP_ON_TYPING) return c;
}
return CommonCodeStyleSettings.WrapOnTyping.NO_WRAP;
}
public void setWrapOnTyping(@NotNull CommonCodeStyleSettings.WrapOnTyping value) {
getCommonSettings().WRAP_ON_TYPING = value.intValue;
}
@NotNull
protected final CommonCodeStyleSettings getCommonSettings() {
return myRootSettings.getCommonSettings(getLanguage());
}
@NotNull
protected final CommonCodeStyleSettings.IndentOptions getIndentOptions(boolean isWritable) {
CommonCodeStyleSettings.IndentOptions indentOptions = getCommonSettings().getIndentOptions();
if (indentOptions == null && isWritable) {
indentOptions = getCommonSettings().initIndentOptions();
}
return indentOptions != null ? indentOptions : myRootSettings.OTHER_INDENT_OPTIONS;
}
@NotNull
protected final <T extends CustomCodeStyleSettings> T getCustomSettings(@NotNull Class<T> settingsClass) {
return myRootSettings.getCustomSettings(settingsClass);
}
protected static WrapType intToWrapType(int wrap) {
return WrapType.byLegacyRepresentation(wrap);
}
protected static int wrapTypeToInt(@NotNull WrapType wrapType) {
return wrapType.getLegacyRepresentation();
}
}
@@ -185,10 +185,6 @@
enabledByDefault="true" isInternal="true" level="WARNING"
implementationClass="org.jetbrains.idea.devkit.inspections.UnregisteredNamedColorInspection"/>
<intentionAction>
<className>org.jetbrains.idea.devkit.codeStyle.bean.CodeStyleBeanIntention</className>
</intentionAction>
<moduleConfigurationEditorProvider implementation="org.jetbrains.idea.devkit.module.PluginModuleEditorsProvider"/>
<implicitUsageProvider implementation="org.jetbrains.idea.devkit.inspections.DevKitImplicitUsageProvider"/>
<psi.referenceContributor language="XML" implementation="org.jetbrains.idea.devkit.dom.impl.I18nReferenceContributor"/>
@@ -1,251 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.codeStyle.bean;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
public class CodeStyleBeanAccessorGenerator {
private enum ValueType {
BOOLEAN,
INT,
STRING,
WRAP,
BRACE_STYLE,
FORCE_BRACES,
ENUM,
OTHER
}
private final static String BOOL_GETTER_PREFIX = "is";
private final static String GETTER_PREFIX = "get";
private final static String SETTER_PREFIX = "set";
private final @NotNull Field myField;
private final @NotNull Class myContainerClass;
private final @NotNull String myFieldName;
private final @NotNull Set<String> myImports = ContainerUtil.newHashSet();
/**
* Rules for method names which differ from field names for better readability.
*/
private final static Map<String, String> FIELD_TO_METHOD_NAME_MAP = ContainerUtilRt.newHashMap();
static {
addMapping("SPACE_AFTER_SEMICOLON", "SpaceAfterForSemicolon");
addMapping("SPACE_BEFORE_SEMICOLON", "SpaceBeforeForSemicolon");
addMapping("LPAREN", "LeftParen");
addMapping("RPAREN", "RightParen");
addMapping("JD", "JavaDoc");
addMapping("RBRACE", "RightBrace");
addMapping("LBRACE", "LeftBrace");
addMapping("INSTANCEOF", "InstanceOf");
addMapping("DOWHILE", "DoWhile");
addMapping("INDENT_SIZE", "Indent");
addMapping("CONTINUATION_INDENT_SIZE", "ContinuationIndent");
addMapping("PARM", "Param");
}
public CodeStyleBeanAccessorGenerator(@NotNull Field field) {
myField = field;
myContainerClass = field.getDeclaringClass();
myFieldName = field.getName();
}
private static void addMapping(@NotNull String fieldName, @NotNull String methodName) {
FIELD_TO_METHOD_NAME_MAP.put(fieldName, methodName);
}
String getGetterName() {
return (getValueType() == ValueType.BOOLEAN ? BOOL_GETTER_PREFIX : GETTER_PREFIX) + fieldToMethodName();
}
private ValueType getValueType() {
Class<?> fieldType = myField.getType();
String name = fieldType.getName();
if (fieldType.isPrimitive()) {
if ("int".equals(name)) {
if (myFieldName.endsWith("_WRAP")) {
return ValueType.WRAP;
}
else if (myFieldName.endsWith("BRACE_STYLE")) {
return ValueType.BRACE_STYLE;
}
else if (myFieldName.endsWith("_BRACE_FORCE")) {
return ValueType.FORCE_BRACES;
}
return ValueType.INT;
}
else if ("boolean".equals(name)) {
return ValueType.BOOLEAN;
}
}
else if ("java.lang.String".equals(name)) {
return ValueType.STRING;
}
else if (fieldType.isEnum()) {
return ValueType.ENUM;
}
return ValueType.OTHER;
}
private String fieldToMethodName() {
if (FIELD_TO_METHOD_NAME_MAP.containsKey(myFieldName)) return FIELD_TO_METHOD_NAME_MAP.get(myFieldName);
StringBuilder nameBuilder = new StringBuilder();
String[] chunks = myFieldName.split("_");
for (String chunk : chunks) {
appendNamePart(nameBuilder, chunk);
}
return nameBuilder.toString();
}
@SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
private static void appendNamePart(@NotNull StringBuilder nameBuilder, @NotNull String chunk) {
if (chunk.length() > 0) {
if (FIELD_TO_METHOD_NAME_MAP.containsKey(chunk)) {
nameBuilder.append(FIELD_TO_METHOD_NAME_MAP.get(chunk));
}
else {
nameBuilder.append(chunk.substring(0, 1).toUpperCase());
if (chunk.length() > 1) {
nameBuilder.append(chunk.substring(1).toLowerCase());
}
}
}
}
String getSetterName() {
return SETTER_PREFIX + fieldToMethodName();
}
@Nullable
String getTypeString() {
Class<?> fieldType = myField.getType();
ValueType valueType = getValueType();
switch (valueType) {
case WRAP:
myImports.add("com.intellij.formatting.WrapType");
return "WrapType";
case BRACE_STYLE:
myImports.add("com.intellij.formatting.BraceStyle");
return "BraceStyle";
case FORCE_BRACES:
myImports.add("com.intellij.formatting.ForceBraces");
return "ForceBraces";
case INT:
case BOOLEAN:
return fieldType.getSimpleName();
case ENUM:
case STRING:
myImports.add(fieldType.getCanonicalName());
return fieldType.getSimpleName();
case OTHER:
return null;
}
return null;
}
boolean isFieldSupported() {
return myField.getType().getCanonicalName() != null &&
myField.getAnnotation(Deprecated.class) == null;
}
String getContainerClassAccessor(boolean isWriteAccess) {
if (myContainerClass == CommonCodeStyleSettings.class) {
return "getCommonSettings()";
}
else if (myContainerClass == CommonCodeStyleSettings.IndentOptions.class) {
return "getIndentOptions(" + isWriteAccess + ")";
}
myImports.add(myContainerClass.getName());
return "getCustomSettings(" + myContainerClass.getSimpleName() + ".class)";
}
void generateGetter(StringBuilder output) {
String typeString = getTypeString();
if (typeString != null) {
output
.append("public ")
.append(getTypeString())
.append(' ')
.append(getGetterName())
.append("() {\n");
final ValueType valueType = getValueType();
if (valueType == ValueType.WRAP) {
output
.append("return intToWrapType(")
.append(getContainerClassAccessor(false))
.append(".").append(myFieldName)
.append(");\n");
}
else if (valueType == ValueType.BRACE_STYLE || valueType == ValueType.FORCE_BRACES) {
output
.append("return ").append(typeString).append(".fromInt(")
.append(getContainerClassAccessor(false))
.append(".").append(myFieldName)
.append(");\n");
}
else {
output
.append("return ")
.append((getContainerClassAccessor(false)))
.append(".").append(myFieldName).append(";\n");
}
output
.append("}\n");
}
else {
output.append("\n // TODO: Implement ")
.append(myFieldName)
.append(" getter manually (unsupported type).\n");
}
}
void generateSetter(StringBuilder output) {
final String typeString = getTypeString();
if (typeString != null) {
output
.append("public void ")
.append(getSetterName())
.append("(")
.append(typeString).append(" value")
.append("){");
output
.append(getContainerClassAccessor(true))
.append(".").append(myFieldName).append("= ");
final ValueType valueType = getValueType();
if (valueType == ValueType.WRAP) {
output.append("wrapTypeToInt(");
}
output.append("value");
if (valueType == ValueType.BRACE_STYLE || valueType == ValueType.FORCE_BRACES) {
output.append(".intValue()");
}
if (valueType == ValueType.WRAP) {
output.append(")");
}
output.append(";");
output
.append("}\n");
}
else {
output.append("\n // TODO: Implement ")
.append(myFieldName)
.append(" setter manually (unsupported type).\n");
}
}
@NotNull
Set<String> getImports() {
return myImports;
}
}
@@ -1,169 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.codeStyle.bean;
import com.intellij.application.options.IndentOptionsEditor;
import com.intellij.application.options.SmartIndentOptionsEditor;
import com.intellij.lang.Language;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class CodeStyleBeanGenerator {
private final PsiFile myFile;
private final PsiClass myBeanClass;
private final Language myLanguage;
private final Set<String> myImports = ContainerUtil.newHashSet();
public CodeStyleBeanGenerator(@NotNull PsiFile file, @NotNull PsiClass aClass, @NotNull Language language) {
myFile = file;
myBeanClass = aClass;
myLanguage = language;
}
public String generateBeanMethods() {
StringBuilder sb = new StringBuilder();
generateMethodsFor(CommonCodeStyleSettings.IndentOptions.class, sb, getSupportedIndentOptions());
generateMethodsFor(CommonCodeStyleSettings.class, sb, getSupportedFields());
for (CustomCodeStyleSettings customSettings : getCustomSettings()) {
generateMethodsFor(customSettings.getClass(), sb, null);
}
return sb.toString();
}
private Set<String> getSupportedIndentOptions() {
LanguageCodeStyleSettingsProvider provider = LanguageCodeStyleSettingsProvider.forLanguage(myLanguage);
if (provider == null) return Collections.emptySet();
Set<String> indentOptions = ContainerUtil.newHashSet();
IndentOptionsEditor editor = provider.getIndentOptionsEditor();
if (editor != null) {
indentOptions.add("TAB_SIZE");
indentOptions.add("USE_TAB_CHARACTER");
indentOptions.add("INDENT_SIZE");
if (editor instanceof SmartIndentOptionsEditor) {
indentOptions.add("CONTINUATION_INDENT_SIZE");
indentOptions.add("SMART_TABS");
indentOptions.add("KEEP_INDENTS_ON_EMPTY_LINES");
}
}
return indentOptions;
}
private Set<String> getSupportedFields() {
LanguageCodeStyleSettingsProvider provider = LanguageCodeStyleSettingsProvider.forLanguage(myLanguage);
return provider == null ? Collections.emptySet() : provider.getSupportedFields();
}
private void generateMethodsFor(Class codeStyleClass, StringBuilder output, @Nullable Set<String> supportedFields) {
for (Field field : getCodeStyleFields(codeStyleClass)) {
CodeStyleBeanAccessorGenerator accessorGenerator = new CodeStyleBeanAccessorGenerator(field);
String fieldName = field.getName();
if ((supportedFields == null || supportedFields.contains(fieldName)) &&
!beanContainsField(fieldName) &&
accessorGenerator.isFieldSupported()) {
String setterName = accessorGenerator.getSetterName();
if (!superClassContainsMethod(setterName)) {
accessorGenerator.generateGetter(output);
}
String getterName = accessorGenerator.getGetterName();
if (!superClassContainsMethod(getterName)) {
accessorGenerator.generateSetter(output);
}
}
myImports.addAll(accessorGenerator.getImports());
}
}
private static List<Field> getCodeStyleFields(Class codeStyleClass) {
List<Field> fields = new ArrayList<>();
for (Field field : codeStyleClass.getFields()) {
if (isPublic(field) && !isFinal(field)) {
fields.add(field);
}
}
return fields;
}
private static boolean isPublic(final Field field) {
return (field.getModifiers() & Modifier.PUBLIC) != 0;
}
private static boolean isFinal(final Field field) {
return (field.getModifiers() & Modifier.FINAL) != 0;
}
private boolean beanContainsField(@NotNull String fieldName) {
PsiMethod[] methods = myBeanClass.getMethods();
for (PsiMethod method : methods) {
if (methodContainsField(method, fieldName)) return true;
}
return false;
}
private boolean superClassContainsMethod(@NotNull String methodName) {
PsiClass superClass = myBeanClass.getSuperClass();
if (superClass != null) {
for (PsiMethod baseMethod : superClass.getMethods()) {
if (methodName.equals(baseMethod.getName())) return true;
}
}
return false;
}
private static boolean methodContainsField(@NotNull PsiMethod method, @NotNull String fieldName) {
final Ref<Boolean> found = Ref.create(false);
PsiRecursiveElementVisitor visitor = new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof PsiIdentifier && fieldName.equals(element.getText())) {
found.set(true);
}
else {
super.visitElement(element);
}
}
};
method.accept(visitor);
return found.get();
}
private List<CustomCodeStyleSettings> getCustomSettings() {
CodeStyleSettings rootSettings = new CodeStyleSettings();
List<CustomCodeStyleSettings> customSettingsList = new ArrayList<>();
addCustomSettings(customSettingsList, rootSettings, CodeStyleSettingsProvider.EXTENSION_POINT_NAME.getExtensionList());
addCustomSettings(customSettingsList, rootSettings, LanguageCodeStyleSettingsProvider.getSettingsPagesProviders());
return customSettingsList;
}
private void addCustomSettings(@NotNull List<CustomCodeStyleSettings> list,
@NotNull CodeStyleSettings rootSettings,
@NotNull List<? extends CodeStyleSettingsProvider> providerList) {
for (CodeStyleSettingsProvider provider : providerList) {
if (provider.getLanguage() == myLanguage) {
CustomCodeStyleSettings customSettings = provider.createCustomSettings(rootSettings);
if (customSettings != null && resolveClass(customSettings.getClass().getName(), myFile) != null) {
list.add(customSettings);
}
}
}
}
@Nullable
static PsiClass resolveClass(@NotNull String classFQN, @NotNull PsiFile file) {
PsiResolveHelper resolveHelper = PsiResolveHelper.SERVICE.getInstance(file.getProject());
return resolveHelper.resolveReferencedClass(classFQN, file);
}
Set<String> getImports() {
return myImports;
}
}
@@ -1,144 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.codeStyle.bean;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("SameParameterValue")
public class CodeStyleBeanIntention implements IntentionAction {
@Nls(capitalization = Nls.Capitalization.Sentence)
@NotNull
@Override
public String getText() {
return "Generate CodeStyle methods";
}
@Nls(capitalization = Nls.Capitalization.Sentence)
@NotNull
@Override
public String getFamilyName() {
return "Language plugin";
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
PsiClass beanClass = findBeanClass(file);
if (beanClass != null) {
int offset = editor.getCaretModel().getOffset();
if (beanClass.getTextRange().contains(offset)) {
PsiElement currElement = file.findElementAt(offset);
if (currElement != null && currElement.getParent() == beanClass) {
ASTNode leftBrace = TreeUtil.findSibling(currElement.getNode(), JavaTokenType.RBRACE);
ASTNode rightBrace = TreeUtil.findSiblingBackward(currElement.getNode(), JavaTokenType.LBRACE);
return leftBrace != null && rightBrace != null;
}
}
}
return false;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
PsiClass beanClass = findBeanClass(file);
if (beanClass != null) {
generateAccessors(beanClass, editor, file);
}
}
@Nullable
private static PsiClass findBeanClass(@NotNull PsiFile file) {
if (file instanceof PsiJavaFile) {
PsiClass[] classes = ((PsiJavaFile)file).getClasses();
for (PsiClass javaClass : classes) {
if (isCodeStyleBean(javaClass)) return javaClass;
}
}
return null;
}
private static boolean isCodeStyleBean(@NotNull PsiClass javaClass) {
PsiReferenceList extendsList = javaClass.getExtendsList();
if (extendsList != null) {
for (PsiClassType type : extendsList.getReferencedTypes()) {
if ("CodeStyleBean".equals(type.getClassName())) return true;
}
}
return false;
}
@Override
public boolean startInWriteAction() {
return true;
}
private static void generateAccessors(@NotNull PsiClass beanClass, @NotNull Editor editor, @NotNull PsiFile file) {
Project project = editor.getProject();
if (project != null) {
int offset = editor.getCaretModel().getOffset();
Language language = getLanguage(beanClass, file);
if (language != null) {
CodeStyleBeanGenerator beanGenerator = new CodeStyleBeanGenerator(file, beanClass, language);
String accessorsText = beanGenerator.generateBeanMethods();
editor.getDocument().insertString(offset, accessorsText);
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
CodeStyleManager.getInstance(project).reformatText(file, offset, offset + accessorsText.length());
for (String requiredImport : beanGenerator.getImports()) {
addImport(file, beanClass, requiredImport);
}
}
}
}
private static void addImport(@NotNull PsiFile file, @NotNull PsiClass beanClass, @NotNull String classFQN) {
PsiClass psiClass = CodeStyleBeanGenerator.resolveClass(classFQN, file);
if (psiClass != null) {
JavaCodeStyleManager.getInstance(beanClass.getProject()).addImport((PsiJavaFile)file, psiClass);
}
}
@Nullable
private static Language getLanguage(@NotNull PsiClass beanClass, @NotNull PsiFile file) {
for (PsiMethod method : beanClass.getMethods()) {
if ("getLanguage".equals(method.getName())) {
PsiCodeBlock body = method.getBody();
if (body != null) {
for (PsiStatement statement : body.getStatements()) {
if (statement instanceof PsiReturnStatement) {
PsiExpression retValue = ((PsiReturnStatement)statement).getReturnValue();
if (retValue instanceof PsiReferenceExpression) {
PsiElement psiLangClass = retValue.getFirstChild();
if (psiLangClass != null) {
PsiClass resolved = CodeStyleBeanGenerator.resolveClass(psiLangClass.getText(), file);
if (resolved != null) {
try {
Class langClass = Class.forName(resolved.getQualifiedName());
if (Language.class.isAssignableFrom(langClass)) {
//noinspection unchecked
return Language.findInstance(langClass);
}
}
catch (ClassNotFoundException e) {
// Ignore
}
}
}
}
}
}
}
}
}
return null;
}
}