IDEA-19061 Integrate the Rearranger-plugin into core-IDEA

Basic 'code arrangement' infrastructure is defined
This commit is contained in:
Denis.Zhdanov
2012-07-20 10:15:34 +04:00
parent eccc9f3980
commit c0aa0945c2
30 changed files with 1332 additions and 253 deletions
+3
View File
@@ -4,6 +4,7 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/testSources" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
@@ -12,6 +13,8 @@
<orderEntry type="library" exported="" name="NanoXML" level="project" />
<orderEntry type="module" module-name="indexing-api" exported="" />
<orderEntry type="module" module-name="projectModel-api" exported="" />
<orderEntry type="library" name="JUnit4" level="project" />
<orderEntry type="library" name="Groovy" level="project" />
</component>
</module>
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@ import com.intellij.lang.Language;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.*;
import com.intellij.psi.codeStyle.arrangement.ArrangementRule;
import com.intellij.psi.codeStyle.arrangement.ArrangementRuleUtil;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
import com.intellij.util.xmlb.XmlSerializer;
import org.intellij.lang.annotations.MagicConstant;
@@ -28,6 +30,8 @@ import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
@@ -37,11 +41,14 @@ import java.util.Set;
* @author Rustam Vishnyakov
*/
public class CommonCodeStyleSettings {
private Language myLanguage;
@NotNull private static final String ARRANGEMENT_ELEMENT_NAME = "arrangementRules";
@NotNull private final List<ArrangementRule> myArrangementRules = new ArrayList<ArrangementRule>();
private Language myLanguage;
private CodeStyleSettings myRootSettings;
private IndentOptions myIndentOptions;
private FileType myFileType;
private IndentOptions myIndentOptions;
private FileType myFileType;
private final static String INDENT_OPTIONS_TAG = "indentOptions";
@@ -193,6 +200,10 @@ public class CommonCodeStyleSettings {
myIndentOptions.deserialize(indentOptionsElement);
}
}
Element arrangementRulesContainer = element.getChild(ARRANGEMENT_ELEMENT_NAME);
if (arrangementRulesContainer != null) {
myArrangementRules.addAll(ArrangementRuleUtil.readExternal(arrangementRulesContainer, myLanguage));
}
}
public void writeExternal(Element element) throws WriteExternalException {
@@ -210,6 +221,14 @@ public class CommonCodeStyleSettings {
element.addContent(indentOptionsElement);
}
}
if (!myArrangementRules.isEmpty()) {
Element container = new Element(ARRANGEMENT_ELEMENT_NAME);
ArrangementRuleUtil.writeExternal(container, myArrangementRules, myLanguage);
if (!container.getChildren().isEmpty()) {
element.addContent(container);
}
}
}
@Nullable
@@ -1,4 +1,19 @@
package com.intellij.psi.codeStyle.rearranger;
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -9,7 +24,7 @@ import java.util.Collection;
* Represents a processing unit during 'rearrangement' operation. I.e. entry's position can be changed during the processing.
* <p/>
* Example: we can provide a grouping rule for class methods (e.g. getters and setters). Every such method will be represented by
* a {@link RearrangerEntry} then.
* a {@link ArrangementEntry} then.
* <p/>
* The entries can be organised into hierarchies where every sub-hierarchy is independent
* (see {@link #getParent()}, {@link #getChildren()}).
@@ -19,14 +34,14 @@ import java.util.Collection;
* @author Denis Zhdanov
* @since 7/16/12 3:31 PM
*/
public interface RearrangerEntry {
public interface ArrangementEntry {
/**
* @return parent entry, e.g. it would be a class entry for a method entry
* @see #getChildren()
*/
@Nullable
RearrangerEntry getParent();
ArrangementEntry getParent();
/**
* Entries can be organised into hierarchies, that means that only siblings position can be changed during the rearrangement.
@@ -38,7 +53,7 @@ public interface RearrangerEntry {
* @see #getParent()
*/
@NotNull
Collection<? extends RearrangerEntry> getChildren();
Collection<? extends ArrangementEntry> getChildren();
/**
* @return start offset of the current entry (inclusive) within the target document. Rearranger engine uses this information
@@ -0,0 +1,76 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType;
import org.jetbrains.annotations.NotNull;
/**
* Container for the strategies to be used during file entries arrangement.
* <p/>
* Example: we can define a rule like 'private final non-static fields' or 'public static methods' etc.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 7/17/12 11:07 AM
*/
public class ArrangementRule {
@NotNull private final ArrangementEntryMatcher myMatcher;
@NotNull private final ArrangementEntrySortType mySortType;
public ArrangementRule(@NotNull ArrangementEntryMatcher matcher) {
this(matcher, ArrangementEntrySortType.NO_SORT);
}
public ArrangementRule(@NotNull ArrangementEntryMatcher matcher, @NotNull ArrangementEntrySortType type) {
myMatcher = matcher;
mySortType = type;
}
@NotNull
public ArrangementEntryMatcher getMatcher() {
return myMatcher;
}
@NotNull
public ArrangementEntrySortType getSorter() {
return mySortType;
}
@Override
public int hashCode() {
int result = myMatcher.hashCode();
result = 31 * result + mySortType.hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ArrangementRule that = (ArrangementRule)o;
return mySortType == that.mySortType && myMatcher.equals(that.myMatcher);
}
@Override
public String toString() {
return String.format("matcher: %s, sort type: %s", myMatcher, mySortType);
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Identifies a strategy that can tweak default {@link ArrangementRule arrangement rules} (de)serialization mechanism.
* <p/>
* Implementations of this interface are expected to be thread-safe.
*
* @author Denis Zhdanov
* @since 7/18/12 10:30 AM
*/
public interface ArrangementRuleSerializer {
/**
* Allows to provide custom rule deserialization logic. This method is expected to be consistent with {@link #serialize(ArrangementRule)}.
* <p/>
* <b>Note:</b> it's save to return <code>null</code> if current rearranger doesn't use custom rules (rules over those
* located at the <code>'lang-api'</code>/<code>'lang-impl'</code> modules).
*
* @param element serialized rule
* @return rule de-serialized from the given element;
* <code>null</code> as an indication that current rearranger doesn't provide custom serialization logic
* for the target rule serialized at the given element, i.e. default deserialization algorithm should be used for it
*/
@Nullable
ArrangementRule deserialize(@NotNull Element element);
/**
* Allows to provide custom rule serialization logic. This method is expected to be consistent with {@link #deserialize(Element)}.
* <p/>
* <b>Note:</b> it's save to return <code>null</code> if current rearranger doesn't use custom rules (rules over those
* located at the <code>'lang-api'</code>/<code>'lang-impl'</code> modules).
*
* @param rule rule to serialize
* @return serialized rule;
* <code>null</code> as an indication that no custom serialization logic for the given rule
* is provided by the current rearranger
*/
@Nullable
Element serialize(ArrangementRule rule);
}
@@ -0,0 +1,144 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement;
import com.intellij.lang.Language;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
import com.intellij.psi.codeStyle.arrangement.match.CompositeArrangementEntryMatcher;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Denis Zhdanov
* @since 7/17/12 11:24 AM
*/
public class ArrangementRuleUtil {
private ArrangementRuleUtil() {
}
//region Serialization
@NotNull
public static List<ArrangementRule> readExternal(@NotNull Element element, @NotNull Language language) {
final List<ArrangementRule> result = new ArrayList<ArrangementRule>();
ArrangementRuleSerializer serializer = getSerializer(language);
for (Object child : element.getChildren()) {
ArrangementRule rule = serializer.deserialize((Element)child);
if (rule != null) {
result.add(rule);
}
}
return result;
}
public static void writeExternal(@NotNull Element element, @NotNull List<ArrangementRule> rules, @NotNull Language language) {
if (rules.isEmpty()) {
return;
}
ArrangementRuleSerializer serializer = getSerializer(language);
for (ArrangementRule rule : rules) {
Element e = serializer.serialize(rule);
if (e != null) {
element.addContent(e);
}
}
}
private static ArrangementRuleSerializer getSerializer(@NotNull Language language) {
Rearranger<?> rearranger = Rearranger.EXTENSION.forLanguage(language);
if (rearranger instanceof ArrangementRuleSerializer) {
return new CompositeArrangementRuleSerializer((ArrangementRuleSerializer)rearranger, DefaultArrangementRuleSerializer.INSTANCE);
}
return DefaultArrangementRuleSerializer.INSTANCE;
}
private static class CompositeArrangementRuleSerializer implements ArrangementRuleSerializer {
@NotNull private final List<ArrangementRuleSerializer> mySerializers = new ArrayList<ArrangementRuleSerializer>();
CompositeArrangementRuleSerializer(@NotNull ArrangementRuleSerializer ... serializers) {
mySerializers.addAll(Arrays.asList(serializers));
}
@Nullable
@Override
public ArrangementRule deserialize(@NotNull Element element) {
for (ArrangementRuleSerializer serializer : mySerializers) {
ArrangementRule rule = serializer.deserialize(element);
if (rule != null) {
return rule;
}
}
return null;
}
@Nullable
@Override
public Element serialize(ArrangementRule rule) {
for (ArrangementRuleSerializer serializer : mySerializers) {
Element element = serializer.serialize(rule);
if (element != null) {
return element;
}
}
return null;
}
}
//endregion
//region Matchers composition
@NotNull
public static ArrangementEntryMatcher or(@NotNull ArrangementEntryMatcher... matchers) {
return combine(CompositeArrangementEntryMatcher.Operator.OR, matchers);
}
@NotNull
public static ArrangementEntryMatcher and(@NotNull ArrangementEntryMatcher... matchers) {
return combine(CompositeArrangementEntryMatcher.Operator.AND, matchers);
}
@NotNull
private static ArrangementEntryMatcher combine(@NotNull CompositeArrangementEntryMatcher.Operator operator,
@NotNull ArrangementEntryMatcher... matchers)
{
CompositeArrangementEntryMatcher composite = null;
for (ArrangementEntryMatcher matcher : matchers) {
if (matcher instanceof CompositeArrangementEntryMatcher && ((CompositeArrangementEntryMatcher)(matcher)).getOperator() == operator) {
composite = (CompositeArrangementEntryMatcher)matcher;
break;
}
}
if (composite == null) {
return new CompositeArrangementEntryMatcher(operator, matchers);
}
for (ArrangementEntryMatcher matcher : matchers) {
if (matcher != composite) {
composite.addMatcher(matcher);
}
}
return composite;
}
//endregion
}
@@ -0,0 +1,82 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
import com.intellij.psi.codeStyle.arrangement.match.serialization.DefaultArrangementEntryMatcherSerializer;
import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Denis Zhdanov
* @since 7/18/12 10:37 AM
*/
public class DefaultArrangementRuleSerializer implements ArrangementRuleSerializer {
public static final ArrangementRuleSerializer INSTANCE = new DefaultArrangementRuleSerializer();
@NotNull @NonNls private static final String RULE_ELEMENT_NAME = "rule";
@NotNull @NonNls private static final String MATCHER_ELEMENT_NAME = "match";
@NotNull @NonNls private static final String SORT_TYPE_ELEMENT_NAME = "sort";
@NotNull private final DefaultArrangementEntryMatcherSerializer myMatcherSerializer = new DefaultArrangementEntryMatcherSerializer();
@Nullable
@Override
public ArrangementRule deserialize(@NotNull Element element) {
Element matcherElement = element.getChild(MATCHER_ELEMENT_NAME);
if (matcherElement == null) {
return null;
}
ArrangementEntryMatcher matcher = null;
for (Object o : matcherElement.getChildren()) {
matcher = myMatcherSerializer.deserialize((Element)o);
if (matcher != null) {
break;
}
}
if (matcher == null) {
return null;
}
Element sortElement = element.getChild(SORT_TYPE_ELEMENT_NAME);
ArrangementEntrySortType sortType = ArrangementEntrySortType.NO_SORT;
if (sortElement != null) {
sortType = ArrangementEntrySortType.valueOf(sortElement.getText());
}
return new ArrangementRule(matcher, sortType);
}
@Nullable
@Override
public Element serialize(@NotNull ArrangementRule rule) {
Element matcherElement = myMatcherSerializer.serialize(rule.getMatcher());
if (matcherElement == null) {
return null;
}
Element result = new Element(RULE_ELEMENT_NAME);
result.addContent(new Element(MATCHER_ELEMENT_NAME).addContent(matcherElement));
result.addContent(new Element(SORT_TYPE_ELEMENT_NAME).setText(rule.getSorter().toString()));
return result;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement;
import org.jetbrains.annotations.Nullable;
/**
* @author Denis Zhdanov
* @since 7/19/12 6:13 PM
*/
public interface NameAwareArrangementEntry extends ArrangementEntry {
@Nullable
String getName();
}
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement;
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Encapsulates language-specific rearrangement logic.
* <p/>
* Implementations of this interface are expected to be thread-safe.
*
* @author Denis Zhdanov
* @since 7/16/12 3:23 PM
* @param <E> entry type
*/
public interface Rearranger<E extends ArrangementEntry> {
LanguageExtension<Rearranger<?>> EXTENSION = new LanguageExtension<Rearranger<?>>("com.intellij.rearranger.facade");
/**
* Allows to build rearranger-interested data for the given element.
*
* @param root root element which children should be parsed for the rearrangement
* @param range target offsets range to use for filtering given root's children
* @return given root's children that are subject for further rearrangement
*/
@NotNull
Collection<E> parse(@NotNull PsiElement root, @NotNull TextRange range);
}
@@ -13,20 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger;
package com.intellij.psi.codeStyle.arrangement;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Stands for the {@link RearrangerEntry} which provides information about its type.
* Stands for the {@link ArrangementEntry} which provides information about its type.
* <p/>
* Implementations of this interface are not obliged to be thread-safe.
*
* @author Denis Zhdanov
* @since 7/17/12 11:17 AM
*/
public interface TypeAwareRearrangerEntry extends RearrangerEntry {
public interface TypeAwareArrangementEntry extends ArrangementEntry {
@NotNull
RearrangerEntryType getType();
@Nullable
ArrangementEntryType getType();
}
@@ -13,29 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger;
package com.intellij.psi.codeStyle.arrangement.match;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
import com.intellij.psi.codeStyle.arrangement.ArrangementRule;
import org.jetbrains.annotations.NotNull;
/**
* Identifies a strategy which can be used for grouping {@link RearrangerEntry entries}.
* Defines a contract for strategy that determines if an {@link ArrangementRule arrangement rule} matches particular
* {@link ArrangementEntry arrangement entry}.
* <p/>
* Example: we can define a rule like 'private final non-static fields' or 'public static methods' etc.
* Implementations of this interface are expected to provide correct {@link #equals(Object)} & {@link #hashCode()} implementations.
* <p/>
* Implementations of this interface are expected to be thread-safe.
*
* @author Denis Zhdanov
* @since 7/17/12 11:07 AM
* @since 7/18/12 12:02 PM
*/
public interface RearrangerRule {
public interface ArrangementEntryMatcher {
/**
* Allows to check if given entry is matched by the current rule.
* <p/>
* Example: entry like 'public final field' should be matched by a 'final fields' rule but not matched by a 'private fields' rule.
*
*
* @param entry entry to check
* @return <code>true</code> if given entry is matched by the current rule; <code>false</code> otherwise
*/
boolean isMatched(@NotNull RearrangerEntry entry);
boolean isMatched(@NotNull ArrangementEntry entry);
}
@@ -13,19 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger;
package com.intellij.psi.codeStyle.arrangement.match;
import com.intellij.psi.codeStyle.rearranger.RearrangerEntry;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
/**
* Enumerates all possible {@link RearrangerEntry entry} types.
* Enumerates all possible {@link ArrangementEntry entry} types.
* <p/>
* This enum is expected to be populated every time new entry type is introduced.
*
* @author Denis Zhdanov
* @since 7/17/12 11:14 AM
*/
public enum RearrangerEntryType {
public enum ArrangementEntryType {
CLASS, FIELD, METHOD
}
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger;
package com.intellij.psi.codeStyle.arrangement.match;
/**
* @author Denis Zhdanov
* @since 7/17/12 8:54 PM
*/
public enum RearrangerModifier {
public enum ArrangementModifier {
//region Visibility
PUBLIC, PROTECTED, PRIVATE, PACKAGE_PRIVATE,
@@ -0,0 +1,68 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
import com.intellij.psi.codeStyle.arrangement.NameAwareArrangementEntry;
import org.jetbrains.annotations.NotNull;
/**
* @author Denis Zhdanov
* @since 7/19/12 6:36 PM
*/
public class ByNameArrangementEntryMatcher implements ArrangementEntryMatcher {
@NotNull private final String myPattern;
public ByNameArrangementEntryMatcher(@NotNull String pattern) {
myPattern = pattern;
}
@Override
public boolean isMatched(@NotNull ArrangementEntry entry) {
if (entry instanceof NameAwareArrangementEntry) {
String name = ((NameAwareArrangementEntry)entry).getName();
if (name != null) {
return name.matches(myPattern);
}
}
return false;
}
@NotNull
public String getPattern() {
return myPattern;
}
@Override
public int hashCode() {
return myPattern.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ByNameArrangementEntryMatcher that = (ByNameArrangementEntryMatcher)o;
return myPattern.equals(that.myPattern);
}
@Override
public String toString() {
return String.format("with name like '%s'", myPattern);
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
import com.intellij.psi.codeStyle.arrangement.TypeAwareArrangementEntry;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Set;
/**
* Filters {@link ArrangementEntry entries} by {@link TypeAwareArrangementEntry#getType() their types}.
* <p/>
* <b>Note:</b> type-unaware entry will not be matched by the current rule.
* <p/>
* Thread-safe.
*
* @author Denis Zhdanov
* @since 7/17/12 11:19 AM
*/
public class ByTypeArrangementEntryMatcher implements ArrangementEntryMatcher {
@NotNull private final Set<ArrangementEntryType> myTypes = EnumSet.noneOf(ArrangementEntryType.class);
public ByTypeArrangementEntryMatcher(@NotNull ArrangementEntryType... interestedTypes) {
this(Arrays.asList(interestedTypes));
}
public ByTypeArrangementEntryMatcher(@NotNull Collection<ArrangementEntryType> interestedTypes) {
myTypes.addAll(interestedTypes);
}
@Override
public boolean isMatched(@NotNull ArrangementEntry entry) {
if (entry instanceof TypeAwareArrangementEntry) {
return myTypes.contains(((TypeAwareArrangementEntry)(entry)).getType());
}
return false;
}
@NotNull
public Set<ArrangementEntryType> getTypes() {
return myTypes;
}
@Override
public int hashCode() {
return myTypes.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ByTypeArrangementEntryMatcher that = (ByTypeArrangementEntryMatcher)o;
return myTypes.equals(that.myTypes);
}
@Override
public String toString() {
return String.format("of type '%s'", myTypes);
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* @author Denis Zhdanov
* @since 7/17/12 11:26 AM
*/
public class CompositeArrangementEntryMatcher implements ArrangementEntryMatcher {
@NotNull private final Set<ArrangementEntryMatcher> myMatchers = new HashSet<ArrangementEntryMatcher>();
@NotNull private final Operator myOperator;
public CompositeArrangementEntryMatcher(@NotNull Operator operator, @NotNull ArrangementEntryMatcher... matchers) {
myOperator = operator;
myMatchers.addAll(Arrays.asList(matchers));
}
@Override
public boolean isMatched(@NotNull ArrangementEntry entry) {
for (ArrangementEntryMatcher matcher : myMatchers) {
boolean matched = matcher.isMatched(entry);
if (matched && myOperator == Operator.OR) {
return true;
}
else if (!matched && myOperator == Operator.AND) {
return false;
}
}
return myOperator == Operator.AND;
}
@NotNull
public Operator getOperator() {
return myOperator;
}
@NotNull
public Collection<ArrangementEntryMatcher> getMatchers() {
return myMatchers;
}
public void addMatcher(@NotNull ArrangementEntryMatcher rule) {
myMatchers.add(rule);
}
@Override
public int hashCode() {
int result = myMatchers.hashCode();
result = 31 * result + myOperator.hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CompositeArrangementEntryMatcher matcher = (CompositeArrangementEntryMatcher)o;
if (!myMatchers.equals(matcher.myMatchers)) return false;
if (myOperator != matcher.myOperator) return false;
return true;
}
@Override
public String toString() {
return String.format("%s of those: %s", myOperator == Operator.AND ? "all" : "any", myMatchers);
}
public enum Operator {AND, OR}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
import org.jetbrains.annotations.NotNull;
/**
* @author Denis Zhdanov
* @since 7/17/12 8:57 PM
*/
public interface ModifierAwareArrangementEntry extends ArrangementEntry {
@NotNull
ArrangementModifier getModifier();
}
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger;
package com.intellij.psi.codeStyle.arrangement.match.serialization;
import org.jetbrains.annotations.NotNull;
/**
* @author Denis Zhdanov
* @since 7/17/12 8:57 PM
* @since 7/19/12 12:45 PM
*/
public interface ModifierAwareRearrangerEntry extends RearrangerEntry {
public enum ArrangementEntryMatcherSerializationTag {
@NotNull
RearrangerModifier getModifier();
TYPE, MODIFIER, OR, AND, NAME
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match.serialization;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* Strategy that knows how to serialize {@link ArrangementEntryMatcher} objects of particular class.
* <p/>
* Implementations of this interface are expected to be thread-safe.
*
* @author Denis Zhdanov
* @since 7/19/12 12:31 PM
*/
public interface ArrangementEntryMatcherSerializer<T extends ArrangementEntryMatcher> {
/**
* @return class of the target matcher that can be processed by the current serializer
*/
@NotNull
Class<T> getMatcherClass();
/**
* @return allowed element names of the serialized matcher. Are expected to be unique between
* {@link ArrangementEntryMatcherSerializer} implementations
*/
@NotNull
Set<ArrangementEntryMatcherSerializationTag> getTags();
@NotNull
Element serialize(@NotNull T matcher);
/**
* Allows to deserialize target matcher object serialized previously via {@link #serialize(ArrangementEntryMatcher)}
*
* @param element serialized representation of the target matcher
* @return de-serialized matcher instance
* @throws IllegalArgumentException if current strategy doesn't know how to deserialize target matcher from the given
* element (the exception must not be thrown if given element's name is in
* {@link #getTags() target element names})
*/
@NotNull
T deserialize(@NotNull Element element) throws IllegalArgumentException;
}
@@ -0,0 +1,54 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match.serialization;
import com.intellij.psi.codeStyle.arrangement.match.ByNameArrangementEntryMatcher;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
import java.util.Set;
/**
* @author Denis Zhdanov
* @since 7/19/12 6:40 PM
*/
public class ByNameArrangementEntryMatcherSerializer implements ArrangementEntryMatcherSerializer<ByNameArrangementEntryMatcher> {
@NotNull
@Override
public Class<ByNameArrangementEntryMatcher> getMatcherClass() {
return ByNameArrangementEntryMatcher.class;
}
@NotNull
@Override
public Set<ArrangementEntryMatcherSerializationTag> getTags() {
return EnumSet.of(ArrangementEntryMatcherSerializationTag.NAME);
}
@NotNull
@Override
public Element serialize(@NotNull ByNameArrangementEntryMatcher matcher) {
return new Element(ArrangementEntryMatcherSerializationTag.NAME.toString()).setText(matcher.getPattern());
}
@NotNull
@Override
public ByNameArrangementEntryMatcher deserialize(@NotNull Element element) throws IllegalArgumentException {
return new ByNameArrangementEntryMatcher(element.getText());
}
}
@@ -0,0 +1,81 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match.serialization;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
import com.intellij.psi.codeStyle.arrangement.match.ByTypeArrangementEntryMatcher;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
import java.util.Set;
/**
* @author Denis Zhdanov
* @since 7/19/12 12:44 PM
*/
public class ByTypeArrangementEntryMatcherSerializer implements ArrangementEntryMatcherSerializer<ByTypeArrangementEntryMatcher> {
private static final String SEPARATOR = "|";
@NotNull
@Override
public Class<ByTypeArrangementEntryMatcher> getMatcherClass() {
return ByTypeArrangementEntryMatcher.class;
}
@NotNull
@Override
public Set<ArrangementEntryMatcherSerializationTag> getTags() {
return EnumSet.of(ArrangementEntryMatcherSerializationTag.TYPE);
}
@NotNull
@Override
public Element serialize(@NotNull ByTypeArrangementEntryMatcher matcher) {
StringBuilder buffer = new StringBuilder();
for (ArrangementEntryType type : matcher.getTypes()) {
buffer.append(type).append(SEPARATOR);
}
if (buffer.length() > 0) {
buffer.setLength(buffer.length() - 1);
}
return new Element(ArrangementEntryMatcherSerializationTag.TYPE.toString()).setText(buffer.toString());
}
@NotNull
@Override
public ByTypeArrangementEntryMatcher deserialize(@NotNull Element element) throws IllegalArgumentException {
if (!ArrangementEntryMatcherSerializationTag.TYPE.toString().equals(element.getName())) {
throw new IllegalArgumentException(String.format(
"Can't deserialize matcher of class %s from an element with name '%s'. Expected name: '%s'",
getMatcherClass(), element.getName(), ArrangementEntryMatcherSerializationTag.TYPE.toString()));
}
String text = element.getText();
if (text == null) {
throw new IllegalArgumentException(String.format(
"Can't deserialize matcher of class %s. Reason: no information about target type(s) is found", getMatcherClass()
));
}
Set<ArrangementEntryType> types = EnumSet.noneOf(ArrangementEntryType.class);
for (String s : text.split("\\" + SEPARATOR)) {
types.add(ArrangementEntryType.valueOf(s));
}
return new ByTypeArrangementEntryMatcher(types);
}
}
@@ -0,0 +1,153 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match.serialization;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
import com.intellij.psi.codeStyle.arrangement.match.CompositeArrangementEntryMatcher;
import com.intellij.util.containers.ClassMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Denis Zhdanov
* @since 7/19/12 1:00 PM
*/
public class DefaultArrangementEntryMatcherSerializer {
private static final Logger LOG = Logger.getInstance("#" + DefaultArrangementEntryMatcherSerializer.class.getName());
@NotNull private final ClassMap<ArrangementEntryMatcherSerializer<?>> mySerializers
= new ClassMap<ArrangementEntryMatcherSerializer<?>>();
@NotNull private final Map<String /* element name */, ArrangementEntryMatcherSerializer<?>> myDeserializers =
new HashMap<String, ArrangementEntryMatcherSerializer<?>>();
public DefaultArrangementEntryMatcherSerializer() {
register(new ByTypeArrangementEntryMatcherSerializer());
register(new ByNameArrangementEntryMatcherSerializer());
register(new CompositeSerializer());
}
private void register(@NotNull ArrangementEntryMatcherSerializer<?> serializer) {
mySerializers.put(serializer.getMatcherClass(), serializer);
for (ArrangementEntryMatcherSerializationTag tag : serializer.getTags()) {
ArrangementEntryMatcherSerializer<?> old = myDeserializers.put(tag.toString(), serializer);
assert old == null : String.format("Multiple serializers are registered for the tag %s: %s and %s", tag.toString(), old, serializer);
}
}
@SuppressWarnings("unchecked")
@Nullable
public <T extends ArrangementEntryMatcher> Element serialize(@NotNull T matcher) {
ArrangementEntryMatcherSerializer<T> serializer = (ArrangementEntryMatcherSerializer<T>)mySerializers.get(matcher.getClass());
if (serializer != null) {
return serializer.serialize(matcher);
}
StringBuilder buffer = new StringBuilder();
for (ArrangementEntryMatcherSerializer<?> s : mySerializers.values()) {
buffer.append(s.getMatcherClass()).append(", ");
}
if (buffer.length() > 0) {
buffer.setLength(buffer.length() - 2);
}
LOG.warn(String.format(
"Can't serialize arrangement entry matcher of class '%s'. Reason: no corresponding serializer is registered."
+ "Available serializers can handle the following matchers: '%s'", matcher.getClass(), buffer.toString()
));
return null;
}
@SuppressWarnings("unchecked")
@Nullable
public <T extends ArrangementEntryMatcher> T deserialize(@NotNull Element matcherElement) {
ArrangementEntryMatcherSerializer<T> serializer = (ArrangementEntryMatcherSerializer<T>)myDeserializers.get(matcherElement.getName());
if (serializer != null) {
return serializer.deserialize(matcherElement);
}
StringBuilder buffer = new StringBuilder();
for (String s : myDeserializers.keySet()) {
buffer.append(s).append(", ");
}
if (buffer.length() > 0) {
buffer.setLength(buffer.length() - 2);
}
LOG.warn(String.format(
"Can't deserialize an arrangement entry matcher from matchElement with name '%s'. Reason: only the following elements are supported: %s",
matcherElement.getName(), buffer
));
return null;
}
private class CompositeSerializer implements ArrangementEntryMatcherSerializer<CompositeArrangementEntryMatcher> {
@NotNull
@Override
public Class<CompositeArrangementEntryMatcher> getMatcherClass() {
return CompositeArrangementEntryMatcher.class;
}
@NotNull
@Override
public Set<ArrangementEntryMatcherSerializationTag> getTags() {
return EnumSet.of(ArrangementEntryMatcherSerializationTag.AND, ArrangementEntryMatcherSerializationTag.OR);
}
@NotNull
@Override
public Element serialize(@NotNull CompositeArrangementEntryMatcher matcher) {
ArrangementEntryMatcherSerializationTag tag = matcher.getOperator() == CompositeArrangementEntryMatcher.Operator.AND
? ArrangementEntryMatcherSerializationTag.AND
: ArrangementEntryMatcherSerializationTag.OR;
Element result = new Element(tag.toString());
for (ArrangementEntryMatcher childMatcher : matcher.getMatchers()) {
Element element = DefaultArrangementEntryMatcherSerializer.this.serialize(childMatcher);
if (element != null) {
result.addContent(element);
}
}
return result;
}
@NotNull
@Override
public CompositeArrangementEntryMatcher deserialize(@NotNull Element element) throws IllegalArgumentException {
CompositeArrangementEntryMatcher.Operator operator = ArrangementEntryMatcherSerializationTag.OR.toString().equals(element.getName())
? CompositeArrangementEntryMatcher.Operator.OR
: CompositeArrangementEntryMatcher.Operator.AND;
CompositeArrangementEntryMatcher result = null;
for (Object o : element.getChildren()) {
ArrangementEntryMatcher matcher = DefaultArrangementEntryMatcherSerializer.this.deserialize((Element)o);
if (matcher == null) {
continue;
}
if (result == null) {
result = new CompositeArrangementEntryMatcher(operator, matcher);
}
else {
result.addMatcher(matcher);
}
}
if (result == null) {
throw new IllegalArgumentException(String.format("Can't deserialize a matcher from element '%s'", element));
}
return result;
}
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.sort;
/**
* @author Denis Zhdanov
* @since 7/19/12 6:24 PM
*/
public enum ArrangementEntrySortType {
NO_SORT, BY_NAME
}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.sort;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Defines a contract for a strategy that knows how to sort {@link ArrangementEntry arrangement entries}
* {@link ArrangementEntryMatcher#isMatched(ArrangementEntry) matched} against the same rule using particular
* {@link ArrangementEntrySortType sort type}.
* <p/>
* Implementations of this interface are expected to provide correct {@link #equals(Object)} & {@link #hashCode()} implementations.
* <p/>
* Implementations of this interface are expected to be thread-safe.
*
* @author Denis Zhdanov
* @since 7/18/12 12:41 PM
*/
public interface ArrangementEntrySorter {
/**
* Asks to sort given entries matched against the current rule. Given list defines a default order to be used.
*
* @param entries entries matched against the current rule
*/
void sort(@NotNull List<? extends ArrangementEntry> entries);
}
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.sort;
import com.intellij.psi.codeStyle.arrangement.ArrangementEntry;
import com.intellij.psi.codeStyle.arrangement.NameAwareArrangementEntry;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author Denis Zhdanov
* @since 7/19/12 6:17 PM
*/
public class ByNameArrangementEntrySorter implements ArrangementEntrySorter {
@Override
public void sort(@NotNull List<? extends ArrangementEntry> entries) {
TObjectIntHashMap<ArrangementEntry> weights = new TObjectIntHashMap<ArrangementEntry>();
for (int i = 0; i < entries.size(); i++) {
weights.put(entries.get(i), i);
}
Collections.sort(entries, new MyComparator(weights));
}
private static class MyComparator implements Comparator<ArrangementEntry> {
@NotNull
private final TObjectIntHashMap<ArrangementEntry> myFallbackWeights;
MyComparator(@NotNull TObjectIntHashMap<ArrangementEntry> weights) {
myFallbackWeights = weights;
}
@Override
public int compare(ArrangementEntry o1, ArrangementEntry o2) {
if (o1 instanceof NameAwareArrangementEntry && o2 instanceof NameAwareArrangementEntry) {
String name1 = ((NameAwareArrangementEntry)o1).getName();
String name2 = ((NameAwareArrangementEntry)o1).getName();
if (name1 != null && name2 != null) {
return name1.compareTo(name2);
}
}
return myFallbackWeights.get(o1) - myFallbackWeights.get(o2);
}
}
}
@@ -1,42 +0,0 @@
package com.intellij.psi.codeStyle.rearranger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
/**
* Encapsulates language-specific rearrangement logic.
* <p/>
* Implementations of this interface are expected to be thread-safe.
*
* @author Denis Zhdanov
* @since 7/16/12 3:23 PM
* @param <E> entry type
* @param <R> rule type
*/
public interface RearrangerFacade<E extends RearrangerEntry> {
ExtensionPointName<RearrangerFacade> EP_NAME = ExtensionPointName.create("com.intellij.rearranger.facade");
/**
* Allows to build rearranger-interested data for the given element.
*
* @param root root element which children should be parsed for the rearrangement
* @param range target offsets range to use for filtering given root's children
* @return given root's children that are subject for further rearrangement
*/
@NotNull
Collection<E> parse(@NotNull PsiElement root, @NotNull TextRange range);
/**
* Asks to sort given entries matched against the given rule. Given list defines a default order to be used.
*
* @param entries entries matched against the given rule
* @param rule target rule
*/
void sort(@NotNull List<E> entries, @NotNull RearrangerRule rule);
}
@@ -1,64 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger.rule;
import com.intellij.psi.codeStyle.rearranger.RearrangerEntry;
import com.intellij.psi.codeStyle.rearranger.RearrangerRule;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Denis Zhdanov
* @since 7/17/12 11:26 AM
*/
public class RearrangerCompositeRule implements RearrangerRule {
@NotNull private final List<RearrangerRule> myRules = new ArrayList<RearrangerRule>();
@NotNull private final Operator myOperator;
public RearrangerCompositeRule(@NotNull Operator operator, @NotNull RearrangerRule ... rules) {
myOperator = operator;
myRules.addAll(Arrays.asList(rules));
}
@Override
public boolean isMatched(@NotNull RearrangerEntry entry) {
for (RearrangerRule rule : myRules) {
boolean matched = rule.isMatched(entry);
if (matched && myOperator == Operator.OR) {
return true;
}
else if (!matched && myOperator == Operator.AND) {
return false;
}
}
return myOperator == Operator.AND;
}
@NotNull
public Operator getOperator() {
return myOperator;
}
public void addRule(@NotNull RearrangerRule rule) {
myRules.add(rule);
}
public enum Operator {AND, OR}
}
@@ -1,61 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger.rule;
import com.intellij.psi.codeStyle.rearranger.RearrangerRule;
import org.jetbrains.annotations.NotNull;
/**
* @author Denis Zhdanov
* @since 7/17/12 11:24 AM
*/
public class RearrangerRuleUtil {
private RearrangerRuleUtil() {
}
@NotNull
public static RearrangerRule or(@NotNull RearrangerRule ... rules) {
return combine(RearrangerCompositeRule.Operator.OR, rules);
}
@NotNull
public static RearrangerRule and(@NotNull RearrangerRule ... rules) {
return combine(RearrangerCompositeRule.Operator.AND, rules);
}
@NotNull
private static RearrangerRule combine(@NotNull RearrangerCompositeRule.Operator operator, @NotNull RearrangerRule... rules) {
RearrangerCompositeRule composite = null;
for (RearrangerRule rule : rules) {
if (rule instanceof RearrangerCompositeRule && ((RearrangerCompositeRule)(rule)).getOperator() == operator) {
composite = (RearrangerCompositeRule)rule;
break;
}
}
if (composite == null) {
return new RearrangerCompositeRule(operator, rules);
}
for (RearrangerRule rule : rules) {
if (rule != composite) {
composite.addRule(rule);
}
}
return composite;
}
}
@@ -1,53 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.rearranger.rule;
import com.intellij.psi.codeStyle.rearranger.RearrangerEntry;
import com.intellij.psi.codeStyle.rearranger.RearrangerEntryType;
import com.intellij.psi.codeStyle.rearranger.RearrangerRule;
import com.intellij.psi.codeStyle.rearranger.TypeAwareRearrangerEntry;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Set;
/**
* Filters {@link RearrangerEntry entries} by {@link TypeAwareRearrangerEntry#getType() their types}.
* <p/>
* <b>Note:</b> type-unaware entry will not be matched by the current rule.
* <p/>
* Thread-safe.
*
* @author Denis Zhdanov
* @since 7/17/12 11:19 AM
*/
public class RearrangerTypeRule implements RearrangerRule {
private final Set<RearrangerEntryType> myTypes = EnumSet.noneOf(RearrangerEntryType.class);
public RearrangerTypeRule(@NotNull RearrangerEntryType ... interestedTypes) {
myTypes.addAll(Arrays.asList(interestedTypes));
}
@Override
public boolean isMatched(@NotNull RearrangerEntry entry) {
if (entry instanceof TypeAwareRearrangerEntry) {
return myTypes.contains(((TypeAwareRearrangerEntry)(entry)).getType());
}
return false;
}
}
@@ -0,0 +1,73 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle.arrangement.match;
import com.intellij.psi.codeStyle.arrangement.ArrangementRule;
import com.intellij.psi.codeStyle.arrangement.ArrangementRuleSerializer;
import com.intellij.psi.codeStyle.arrangement.ArrangementRuleUtil;
import com.intellij.psi.codeStyle.arrangement.DefaultArrangementRuleSerializer;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author Denis Zhdanov
* @since 07/18/2012
*/
public class DefaultArrangementRuleSerializerTest {
private ArrangementRuleSerializer mySerializer;
@Before
public void setUp() {
mySerializer = DefaultArrangementRuleSerializer.INSTANCE;
}
@Test
public void simpleMatchers() {
doTest(new ByTypeArrangementEntryMatcher(ArrangementEntryType.CLASS));
doTest(new ByTypeArrangementEntryMatcher(ArrangementEntryType.values()));
}
@Test
public void compositeMatchers() {
doTest(ArrangementRuleUtil.or(
new ByTypeArrangementEntryMatcher(ArrangementEntryType.FIELD),
new ByTypeArrangementEntryMatcher(ArrangementEntryType.METHOD))
);
doTest(ArrangementRuleUtil.and(
ArrangementRuleUtil.or(
new ByTypeArrangementEntryMatcher(ArrangementEntryType.METHOD),
new ByNameArrangementEntryMatcher("get*")
)
));
}
private void doTest(@NotNull ArrangementEntryMatcher matcher) {
doTest(new ArrangementRule(matcher));
}
private void doTest(@NotNull ArrangementRule rule) {
Element element = mySerializer.serialize(rule);
assertNotNull(String.format("Can't serialize rule '%s'", rule), element);
assertEquals(rule, mySerializer.deserialize(element));
}
}