extracted interface, eliminated possible exceptions due to small indent size diversity

This commit is contained in:
Yaroslav Lepenkin
2014-09-10 13:50:28 +04:00
parent 645968cec1
commit 4858542bb0
4 changed files with 172 additions and 127 deletions
@@ -50,7 +50,7 @@ public class IndentOptionsDetector {
if (myDocument != null) {
List<LineIndentInfo> linesInfo = new LineIndentInfoBuilder(myDocument.getCharsSequence()).build();
IndentUsageStatistics stats = new IndentUsageStatistics(linesInfo);
IndentUsageStatistics stats = new IndentUsageStatisticsImpl(linesInfo);
adjustIndentOptions(indentOptions, stats);
}
@@ -80,18 +80,24 @@ public class IndentOptionsDetector {
}
private static int getPositiveIndentSize(@NotNull IndentUsageStatistics stats) {
IndentUsageInfo maxUsedIndentInfo = stats.getMaxUsedIndentInfo(0);
int maxIndentSize = maxUsedIndentInfo.getIndentSize();
if (maxIndentSize == 0) {
maxUsedIndentInfo = stats.getMaxUsedIndentInfo(1);
maxIndentSize = maxUsedIndentInfo.getIndentSize();
int totalIndentSizesDetected = stats.getTotalIndentSizesDetected();
if (totalIndentSizesDetected == 0) return -1;
IndentUsageInfo maxUsedIndentInfo = stats.getKMostUsedIndentInfo(0);
int maxUsedIndentSize = maxUsedIndentInfo.getIndentSize();
if (maxUsedIndentSize == 0) {
if (totalIndentSizesDetected < 1) return -1;
maxUsedIndentInfo = stats.getKMostUsedIndentInfo(1);
maxUsedIndentSize = maxUsedIndentInfo.getIndentSize();
}
if (maxIndentSize <= MAX_INDENT_TO_DETECT) {
int totalUsagesWithoutZeroIndent = stats.getTotalLinesWithLeadingSpaces() - stats.getTimesUsedIndent(0);
if (maxUsedIndentSize <= MAX_INDENT_TO_DETECT) {
int totalUsagesWithoutZeroIndent = stats.getTotalLinesWithLeadingSpaces() - stats.getTimesIndentUsed(0);
double usageRate = (double)maxUsedIndentInfo.getTimesUsed() / totalUsagesWithoutZeroIndent;
if (usageRate > RATE_THRESHOLD) {
return maxIndentSize;
return maxUsedIndentSize;
}
}
@@ -15,126 +15,16 @@
*/
package com.intellij.psi.codeStyle.autodetect;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import gnu.trove.TIntIntHashMap;
import gnu.trove.TIntIntIterator;
import org.jetbrains.annotations.NotNull;
public interface IndentUsageStatistics {
import java.util.Comparator;
import java.util.List;
int getTotalLinesWithLeadingTabs();
public class IndentUsageStatistics {
private static final Comparator<IndentUsageInfo> DECREASING_ORDER = new Comparator<IndentUsageInfo>() {
@Override
public int compare(@NotNull IndentUsageInfo o1, @NotNull IndentUsageInfo o2) {
return o1.getTimesUsed() < o2.getTimesUsed() ? 1 : o1.getTimesUsed() == o2.getTimesUsed() ? 0 : -1;
}
};
int getTotalLinesWithLeadingSpaces();
private List<LineIndentInfo> myLineInfos;
IndentUsageInfo getKMostUsedIndentInfo(int k);
private int myPreviousLineIndent;
private int myPreviousRelativeIndent;
int getTotalIndentSizesDetected();
private int myTotalLinesWithTabs = 0;
private int myTotalLinesWithWhiteSpaces = 0;
int getTimesIndentUsed(int indent);
private TIntIntHashMap myIndentToUsages = new TIntIntHashMap();
private List<IndentUsageInfo> myIndentUsages = ContainerUtil.newArrayList();
private Stack<IndentData> myParentIndents = ContainerUtil.newStack(new IndentData(0, 0));
public IndentUsageStatistics(@NotNull List<LineIndentInfo> lineInfos) {
myLineInfos = lineInfos;
buildIndentToUsagesMap();
myIndentUsages = toIndentUsageList(myIndentToUsages);
ContainerUtil.sort(myIndentUsages, DECREASING_ORDER);
}
@NotNull
private static List<IndentUsageInfo> toIndentUsageList(@NotNull TIntIntHashMap indentToUsages) {
List<IndentUsageInfo> indentUsageInfos = ContainerUtil.newArrayList();
TIntIntIterator it = indentToUsages.iterator();
while (it.hasNext()) {
it.advance();
indentUsageInfos.add(new IndentUsageInfo(it.key(), it.value()));
}
return indentUsageInfos;
}
public void buildIndentToUsagesMap() {
myPreviousLineIndent = 0;
myPreviousRelativeIndent = 0;
for (LineIndentInfo lineInfo : myLineInfos) {
if (lineInfo.isLineWithTabs()) {
myTotalLinesWithTabs++;
}
else if (lineInfo.isLineWithWhiteSpaceIndent()) {
handleWhiteSpaceIndent(lineInfo.getIndentSize());
}
}
}
@NotNull
private IndentData findParentIndent(int indent) {
while (myParentIndents.size() != 1 && myParentIndents.peek().indent > indent) {
myParentIndents.pop();
}
return myParentIndents.peek();
}
private void handleWhiteSpaceIndent(int currentIndent) {
int relativeIndent = currentIndent - myPreviousLineIndent;
if (relativeIndent < 0) {
IndentData indentData = findParentIndent(currentIndent);
myPreviousLineIndent = indentData.indent;
myPreviousRelativeIndent = indentData.relativeIndent;
relativeIndent = currentIndent - myPreviousLineIndent;
}
if (relativeIndent == 0) {
relativeIndent = myPreviousRelativeIndent;
}
else {
myParentIndents.push(new IndentData(currentIndent, relativeIndent));
}
increaseIndentUsage(relativeIndent);
myPreviousRelativeIndent = relativeIndent;
myPreviousLineIndent = currentIndent;
myTotalLinesWithWhiteSpaces++;
}
private void increaseIndentUsage(int relativeIndent) {
int timesUsed = myIndentToUsages.get(relativeIndent);
myIndentToUsages.put(relativeIndent, ++timesUsed);
}
public int getTotalLinesWithLeadingTabs() {
return myTotalLinesWithTabs;
}
public int getTotalLinesWithLeadingSpaces() {
return myTotalLinesWithWhiteSpaces;
}
public IndentUsageInfo getMaxUsedIndentInfo(int rank) {
return myIndentUsages.get(rank);
}
public int getTimesUsedIndent(int indent) {
return myIndentToUsages.get(indent);
}
private static class IndentData {
public final int indent;
public final int relativeIndent;
public IndentData(int indent, int relativeIndent) {
this.indent = indent;
this.relativeIndent = relativeIndent;
}
}
}
@@ -0,0 +1,149 @@
/*
* Copyright 2000-2014 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.autodetect;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import gnu.trove.TIntIntHashMap;
import gnu.trove.TIntIntIterator;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
import java.util.List;
public class IndentUsageStatisticsImpl implements IndentUsageStatistics {
private static final Comparator<IndentUsageInfo> DECREASING_ORDER = new Comparator<IndentUsageInfo>() {
@Override
public int compare(@NotNull IndentUsageInfo o1, @NotNull IndentUsageInfo o2) {
return o1.getTimesUsed() < o2.getTimesUsed() ? 1 : o1.getTimesUsed() == o2.getTimesUsed() ? 0 : -1;
}
};
private List<LineIndentInfo> myLineInfos;
private int myPreviousLineIndent;
private int myPreviousRelativeIndent;
private int myTotalLinesWithTabs = 0;
private int myTotalLinesWithWhiteSpaces = 0;
private TIntIntHashMap myIndentToUsages = new TIntIntHashMap();
private List<IndentUsageInfo> myIndentUsages = ContainerUtil.newArrayList();
private Stack<IndentData> myParentIndents = ContainerUtil.newStack(new IndentData(0, 0));
public IndentUsageStatisticsImpl(@NotNull List<LineIndentInfo> lineInfos) {
myLineInfos = lineInfos;
buildIndentToUsagesMap();
myIndentUsages = toIndentUsageList(myIndentToUsages);
ContainerUtil.sort(myIndentUsages, DECREASING_ORDER);
}
@NotNull
private static List<IndentUsageInfo> toIndentUsageList(@NotNull TIntIntHashMap indentToUsages) {
List<IndentUsageInfo> indentUsageInfos = ContainerUtil.newArrayList();
TIntIntIterator it = indentToUsages.iterator();
while (it.hasNext()) {
it.advance();
indentUsageInfos.add(new IndentUsageInfo(it.key(), it.value()));
}
return indentUsageInfos;
}
public void buildIndentToUsagesMap() {
myPreviousLineIndent = 0;
myPreviousRelativeIndent = 0;
for (LineIndentInfo lineInfo : myLineInfos) {
if (lineInfo.isLineWithTabs()) {
myTotalLinesWithTabs++;
}
else if (lineInfo.isLineWithWhiteSpaceIndent()) {
handleWhiteSpaceIndent(lineInfo.getIndentSize());
}
}
}
@NotNull
private IndentData findParentIndent(int indent) {
while (myParentIndents.size() != 1 && myParentIndents.peek().indent > indent) {
myParentIndents.pop();
}
return myParentIndents.peek();
}
private void handleWhiteSpaceIndent(int currentIndent) {
int relativeIndent = currentIndent - myPreviousLineIndent;
if (relativeIndent < 0) {
IndentData indentData = findParentIndent(currentIndent);
myPreviousLineIndent = indentData.indent;
myPreviousRelativeIndent = indentData.relativeIndent;
relativeIndent = currentIndent - myPreviousLineIndent;
}
if (relativeIndent == 0) {
relativeIndent = myPreviousRelativeIndent;
}
else {
myParentIndents.push(new IndentData(currentIndent, relativeIndent));
}
increaseIndentUsage(relativeIndent);
myPreviousRelativeIndent = relativeIndent;
myPreviousLineIndent = currentIndent;
myTotalLinesWithWhiteSpaces++;
}
private void increaseIndentUsage(int relativeIndent) {
int timesUsed = myIndentToUsages.get(relativeIndent);
myIndentToUsages.put(relativeIndent, ++timesUsed);
}
@Override
public int getTotalLinesWithLeadingTabs() {
return myTotalLinesWithTabs;
}
@Override
public int getTotalLinesWithLeadingSpaces() {
return myTotalLinesWithWhiteSpaces;
}
@Override
public IndentUsageInfo getKMostUsedIndentInfo(int k) {
return myIndentUsages.get(k);
}
@Override
public int getTimesIndentUsed(int indent) {
return myIndentToUsages.get(indent);
}
@Override
public int getTotalIndentSizesDetected() {
return myIndentToUsages.size();
}
private static class IndentData {
public final int indent;
public final int relativeIndent;
public IndentData(int indent, int relativeIndent) {
this.indent = indent;
this.relativeIndent = relativeIndent;
}
}
}
@@ -112,8 +112,8 @@ public class IndentAutoDetectionTest extends LightPlatformCodeInsightTestCase {
configureByFile(getTestName(true) + ".java");
Document document = getDocument(myFile);
List<LineIndentInfo> lines = new LineIndentInfoBuilder(document.getCharsSequence()).build();
IndentUsageStatistics statistics = new IndentUsageStatistics(lines);
return statistics.getMaxUsedIndentInfo(0);
IndentUsageStatistics statistics = new IndentUsageStatisticsImpl(lines);
return statistics.getKMostUsedIndentInfo(0);
}
private static void doTestLineToIndentMapping(@NotNull CharSequence text, int... spacesForLine) {