diff options
author | simonbrandhof <simon.brandhof@gmail.com> | 2010-09-06 14:08:06 +0000 |
---|---|---|
committer | simonbrandhof <simon.brandhof@gmail.com> | 2010-09-06 14:08:06 +0000 |
commit | aeadc1f9129274949daaa57738c7c4550bdfbc7b (patch) | |
tree | 08dadf5ef7474fc41d1d48f74648f1ba8b55f34d /sonar-squid/src/main/java/org/sonar/squid/text | |
download | sonarqube-aeadc1f9129274949daaa57738c7c4550bdfbc7b.tar.gz sonarqube-aeadc1f9129274949daaa57738c7c4550bdfbc7b.zip |
SONAR-236 remove deprecated code from checkstyle plugin + display default value of rule parameters in Q profile console
Diffstat (limited to 'sonar-squid/src/main/java/org/sonar/squid/text')
8 files changed, 878 insertions, 0 deletions
diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/Line.java b/sonar-squid/src/main/java/org/sonar/squid/text/Line.java new file mode 100644 index 00000000000..ef633b4c79f --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/Line.java @@ -0,0 +1,233 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +import org.apache.commons.lang.StringUtils; +import org.sonar.squid.measures.Measurable; +import org.sonar.squid.measures.Metric; + +class Line implements Measurable<Metric> { + + private final int lineIndex; + private int blankLine = 0; + private int line = 1; + private int lineOfCode = 0; + private int commentLine = 0; + private int headerCommentLine = 0; + private int commentBlankLine = 0; + private int commentedOutCodeLine = 0; + private String comment = null; + private StringBuilder stringLine; + private boolean isBlank; + private boolean isThereJavadoc; + private boolean isThereLicenseHeaderComment; + private final static String NOSONAR_TAG = "NOSONAR"; + + Line() { + this.lineIndex = 0; + } + + Line(String stringLine) { + this(); + setString(new StringBuilder(stringLine)); + } + + Line(int lineIndex, StringBuilder stringLine) { + this(lineIndex); + setString(stringLine); + } + + Line(int lineIndex) { + this.lineIndex = lineIndex; + } + + final void setString(StringBuilder stringLine) { + this.stringLine = stringLine; + isBlank = isBlankLine(); + } + + private boolean isBlankLine() { + for (int i = 0; i < stringLine.length(); i++) { + if ( !Character.isWhitespace(stringLine.charAt(i))) { + return false; + } + } + return true; + } + + /** + * {@inheritDoc} + */ + public double getDouble(Metric metric) { + return getInt(metric); + } + + /** + * {@inheritDoc} + */ + public int getInt(Metric metric) { + switch (metric) { + case BLANK_LINES: + return blankLine; + case LINES: + return line; + case LINES_OF_CODE: + return lineOfCode; + case COMMENT_LINES: + return commentLine; + case COMMENTED_OUT_CODE_LINES: + return commentedOutCodeLine; + case COMMENT_BLANK_LINES: + return commentBlankLine; + case HEADER_COMMENT_LINES: + return headerCommentLine; + default: + throw new IllegalStateException("Metric " + metric.name() + " is not available on Line object."); + } + } + + /** + * {@inheritDoc} + */ + public void setMeasure(Metric metric, double measure) { + setMeasure(metric, (int) measure); + } + + /** + * {@inheritDoc} + */ + public void setMeasure(Metric metric, int measure) { + switch (metric) { + case BLANK_LINES: + blankLine = measure; + break; + case LINES_OF_CODE: + lineOfCode = measure; + break; + case COMMENT_LINES: + commentLine = measure; + break; + case COMMENTED_OUT_CODE_LINES: + commentedOutCodeLine = measure; + break; + case COMMENT_BLANK_LINES: + commentBlankLine = measure; + break; + case HEADER_COMMENT_LINES: + headerCommentLine = measure; + break; + case LINES: + throw new IllegalStateException("Metric LINES always equals 1 on a Line and you are not permitted to change this value."); + default: + throw new IllegalStateException("Metric " + metric.name() + " is not suitable for Line object."); + } + } + + void setComment(String comment) { + this.comment = comment; + } + + void setComment(String comment, boolean isJavadoc) { + setComment(comment); + this.isThereJavadoc = isJavadoc; + } + + void setComment(String comment, boolean isJavadoc, boolean isLicenseHeader) { + setComment(comment, isJavadoc); + this.isThereLicenseHeaderComment = isLicenseHeader; + } + + String getString() { + return stringLine.toString(); + } + + boolean isBlank() { + return !isThereComment() && isBlank; + } + + boolean isThereCode() { + if ( !isBlank() && !isThereComment()) { + return true; + } + if (isThereComment() && isThereCodeBeforeOrAfterComment()) { + return true; + } + return false; + } + + private boolean isThereCodeBeforeOrAfterComment() { + if ( !isThereComment()) { + throw new IllegalStateException("You can't call this method when there isn't any comment"); + } + boolean isThereCodeBeforeComment = false; + boolean isThereCodeAfterComment = false; + int commentStartIndex = stringLine.indexOf(comment); + int commentEndIndex = commentStartIndex + comment.length() - 1; + if (commentStartIndex > 0) { + isThereCodeBeforeComment = !StringUtils.isBlank(stringLine.substring(0, commentStartIndex - 1)); + } + if (commentEndIndex > 0 && commentEndIndex != stringLine.length() - 1) { + isThereCodeAfterComment = !StringUtils.isBlank(stringLine.substring(commentEndIndex + 1)); + } + return isThereCodeBeforeComment || isThereCodeAfterComment; + } + + boolean isThereComment() { + return comment != null; + } + + String getComment() { + return comment; + } + + boolean isThereBlankComment() { + if (isThereComment()) { + for (int i = 0; i < comment.length(); i++) { + char character = comment.charAt(i); + if ( !Character.isWhitespace(character) && character != '*' && character != '/') { + return false; + } + } + return true; + } + return false; + } + + boolean isThereJavadoc() { + return isThereJavadoc; + } + + boolean isThereLicenseHeaderComment() { + return isThereLicenseHeaderComment; + } + + boolean isThereNoSonarTag() { + return isThereComment() && comment.contains(NOSONAR_TAG); + } + + int getLineIndex() { + return lineIndex; + } + + void deleteLineContent() { + comment = null; + stringLine = null; + } +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/LineContextHandler.java b/sonar-squid/src/main/java/org/sonar/squid/text/LineContextHandler.java new file mode 100644 index 00000000000..097478c9f85 --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/LineContextHandler.java @@ -0,0 +1,59 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +abstract class LineContextHandler { + + abstract boolean matchToEnd(Line line, StringBuilder pendingLine); + + abstract boolean matchWithEndOfLine(Line line, StringBuilder pendingLine); + + abstract boolean matchToBegin(Line line, StringBuilder pendingLine); + + static boolean matchEndOfString(StringBuilder pendingLine, String end) { + int pendingLineIndex = pendingLine.length() - end.length(); + if (pendingLineIndex < 0) { + return false; + } + for (int endIndex = 0; endIndex < end.length(); endIndex++) { + char endChar = end.charAt(endIndex); + char pendingLineChar = pendingLine.charAt(pendingLineIndex + endIndex); + if (endChar != pendingLineChar) { + return false; + } + } + return true; + } + + static boolean matchEndOfString(StringBuilder pendingLine, char endChar) { + if (pendingLine.length() < 1) { + return false; + } + return pendingLine.charAt(pendingLine.length() - 1) == endChar; + } + + static char getLastCharacter(StringBuilder pendingLine) { + if (pendingLine.length() < 1) { + throw new IllegalStateException("The pending line is empty."); + } + return pendingLine.charAt(pendingLine.length() - 1); + } + +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/LinesFactory.java b/sonar-squid/src/main/java/org/sonar/squid/text/LinesFactory.java new file mode 100644 index 00000000000..6e98de3da35 --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/LinesFactory.java @@ -0,0 +1,139 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +import org.sonar.squid.api.AnalysisException; + +class LinesFactory { + + private final List<Line> lines = new ArrayList<Line>(); + private char lastReadCharacter; + private StringBuilder currentStringBuilder = new StringBuilder(); + private Line currentLine; + private static final char LF = '\n'; + private static final char CR = '\r'; + private static final int EOF = -1; + private LineContextHandler currentHandler; + private LineContextHandler[] handlers; + + LinesFactory(Reader reader, String... additionalSingleLineCommentFlags) { + List<LineContextHandler> tmpHandlers = new ArrayList<LineContextHandler>(); + for (String additionalSingleLineCommentFlag : additionalSingleLineCommentFlags) { + tmpHandlers.add(new SingleLineCommentHandler(additionalSingleLineCommentFlag)); + } + tmpHandlers.add(new SingleLineCommentHandler("//", "*//")); + tmpHandlers.add(new MultiLinesCommentHandler()); + tmpHandlers.add(new LiteralValueHandler('\'')); + tmpHandlers.add(new LiteralValueHandler('"')); + this.handlers = tmpHandlers.toArray(new LineContextHandler[tmpHandlers.size()]); + fillLines(new BufferedReader(reader)); + } + + private void fillLines(Reader reader) { + try { + currentLine = new Line(1); + int nextChar; + do { + nextChar = reader.read(); + if (isEndOfFile(nextChar)) { + notifyHandlersAboutEndOfLine(); + break; + } + lastReadCharacter = (char) nextChar; + if (isEndOfLine(nextChar)) { + popOptionalRemainingEndOfLineChar(reader); + createNewLine(); + continue; + } + appendToStringBuilder(nextChar); + notifyHandlersAboutNewChar(); + } while (true); + } catch (IOException e) { + throw new AnalysisException("Unable to read the source code.", e); + } catch (Exception e) { + throw new AnalysisException("A problem was encountered when analyzing line " + lines.size() + " : '" + + currentStringBuilder.toString() + "'", e); + } + } + + private void popOptionalRemainingEndOfLineChar(Reader reader) throws IOException { + reader.mark(1); + char nextChar = (char) reader.read(); + reader.reset(); + if (isTechnicalCharacter(nextChar) && lastReadCharacter != nextChar) { + reader.read(); + } + } + + private void notifyHandlersAboutNewChar() { + if (currentHandler == null) { + for (LineContextHandler handler : handlers) { + if (handler.matchToBegin(currentLine, currentStringBuilder)) { + currentHandler = handler; + break; + } + } + } else if (currentHandler.matchToEnd(currentLine, currentStringBuilder)) { + currentHandler = null; + } + } + + private void notifyHandlersAboutEndOfLine() { + if (currentHandler != null && currentHandler.matchWithEndOfLine(currentLine, currentStringBuilder)) { + currentHandler = null; + } + } + + private void createNewLine() { + notifyHandlersAboutEndOfLine(); + currentLine.setString(currentStringBuilder); + lines.add(currentLine); + currentLine = new Line(lines.size() + 1); + currentStringBuilder = new StringBuilder(); + } + + private void appendToStringBuilder(int nextChar) { + if (!isTechnicalCharacter(nextChar)) { + currentStringBuilder.append((char) nextChar); + } + } + + private boolean isEndOfFile(int nextChar) { + return nextChar == EOF && currentStringBuilder.length() == 0 && lastReadCharacter != LF; + } + + private boolean isEndOfLine(int nextChar) { + return nextChar == EOF || (char) nextChar == LF || (char) nextChar == CR; + } + + private boolean isTechnicalCharacter(int nextChar) { + return nextChar == LF || nextChar == CR || nextChar == EOF; + } + + List<Line> getLines() { + return lines; + } +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/LiteralValueHandler.java b/sonar-squid/src/main/java/org/sonar/squid/text/LiteralValueHandler.java new file mode 100644 index 00000000000..907c87827c9 --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/LiteralValueHandler.java @@ -0,0 +1,59 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +public class LiteralValueHandler extends LineContextHandler { + + private final char delimiter; + + public LiteralValueHandler(char delimiter) { + this.delimiter = delimiter; + } + + @Override + boolean matchToEnd(Line line, StringBuilder pendingLine) { + return matchEndOfString(pendingLine, delimiter) && evenNumberOfBackSlashBeforeDelimiter(pendingLine); + } + + private boolean evenNumberOfBackSlashBeforeDelimiter(StringBuilder pendingLine) { + int numberOfBackSlashChar = 0; + for (int index = pendingLine.length() - 2; index >= 0; index--) { + if (pendingLine.charAt(index) == '\\') { + numberOfBackSlashChar++; + } else { + break; + } + } + return numberOfBackSlashChar % 2 == 0; + } + + @Override + boolean matchToBegin(Line line, StringBuilder pendingLine) { + if (matchEndOfString(pendingLine, delimiter)) { + return true; + } + return false; + } + + @Override + boolean matchWithEndOfLine(Line line, StringBuilder pendingLine) { + return true; //see http://jira.codehaus.org/browse/SONAR-1555 + } +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/MultiLinesCommentHandler.java b/sonar-squid/src/main/java/org/sonar/squid/text/MultiLinesCommentHandler.java new file mode 100644 index 00000000000..5aeaadd12ce --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/MultiLinesCommentHandler.java @@ -0,0 +1,101 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +public class MultiLinesCommentHandler extends LineContextHandler { + + private StringBuilder currentLineComment; + private boolean isFirstLineOfComment = false; + + private boolean isJavadoc = false; + private boolean isLicenseHeader = false; + + private boolean commentStarted = false; + + private static final String START_COMMENT_TAG = "/*"; + private static final String START_JAVADOC_TAG = "/**"; + private static final String START_GWT_NATIVE_CODE_TAG = "/*-{"; + private static final String END_COMMENT_TAG = "*/"; + + @Override + boolean matchToEnd(Line line, StringBuilder pendingLine) { + if ( !commentStarted) { + throw new IllegalStateException("Method doContextBegin(StringBuilder pendingLine) has not been called first (line = '" + pendingLine + + "')."); + } + currentLineComment.append(getLastCharacter(pendingLine)); + if (isJavaDoc()) { + isJavadoc = true; + } + if (isGwtNativeCode()) { + initProperties(); + return true; + } + boolean match = matchEndOfString(pendingLine, END_COMMENT_TAG); + if (match && !(isFirstLineOfComment && pendingLine.indexOf(START_COMMENT_TAG) + 1 == pendingLine.indexOf(END_COMMENT_TAG))) { + endOfCommentLine(line); + initProperties(); + return true; + } + return false; + } + + private boolean isGwtNativeCode() { + return isFirstLineOfComment && currentLineComment.length() == START_GWT_NATIVE_CODE_TAG.length() + && currentLineComment.toString().equals(START_GWT_NATIVE_CODE_TAG); + } + + private boolean isJavaDoc() { + return isFirstLineOfComment && currentLineComment.length() == START_JAVADOC_TAG.length() + && currentLineComment.toString().equals(START_JAVADOC_TAG); + } + + @Override + boolean matchToBegin(Line line, StringBuilder pendingLine) { + boolean match = matchEndOfString(pendingLine, START_COMMENT_TAG); + if (match) { + isFirstLineOfComment = true; + commentStarted = true; + currentLineComment = new StringBuilder(START_COMMENT_TAG); + isLicenseHeader = (line.getLineIndex() == 1); + } + return match; + } + + @Override + boolean matchWithEndOfLine(Line line, StringBuilder pendingLine) { + endOfCommentLine(line); + return false; + } + + private void endOfCommentLine(Line line) { + line.setComment(currentLineComment.toString(), isJavadoc, isLicenseHeader); + currentLineComment = new StringBuilder(); + isFirstLineOfComment = false; + } + + private void initProperties() { + commentStarted = false; + isJavadoc = false; + isLicenseHeader = false; + currentLineComment = new StringBuilder(); + isFirstLineOfComment = false; + } +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/SingleLineCommentHandler.java b/sonar-squid/src/main/java/org/sonar/squid/text/SingleLineCommentHandler.java new file mode 100644 index 00000000000..f20861a96d8 --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/SingleLineCommentHandler.java @@ -0,0 +1,63 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +public class SingleLineCommentHandler extends LineContextHandler { + + private StringBuilder comment; + + private final String commentStartTag; + private final String commentNotStartTag; + + public SingleLineCommentHandler(String commentStartTag) { + this(commentStartTag, null); + } + + public SingleLineCommentHandler(String commentStartTag, String commentNotStartTag) { + this.commentStartTag = commentStartTag; + this.commentNotStartTag = commentNotStartTag; + } + + @Override + boolean matchToEnd(Line line, StringBuilder pendingLine) { + if (comment == null) { + throw new IllegalStateException("Method doContextBegin(StringBuilder pendingLine) has not been called."); + } + comment.append(getLastCharacter(pendingLine)); + return false; + } + + @Override + boolean matchToBegin(Line line, StringBuilder pendingLine) { + boolean doContextBegin = matchEndOfString(pendingLine, commentStartTag) + && (commentNotStartTag == null || !matchEndOfString(pendingLine, commentNotStartTag)); + if (doContextBegin) { + comment = new StringBuilder(commentStartTag); + } + return doContextBegin; + } + + @Override + boolean matchWithEndOfLine(Line line, StringBuilder pendingLine) { + line.setComment(comment.toString()); + comment = null; + return true; + } +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/Source.java b/sonar-squid/src/main/java/org/sonar/squid/text/Source.java new file mode 100644 index 00000000000..5087aaba331 --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/Source.java @@ -0,0 +1,128 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.sonar.squid.measures.Metric; +import org.sonar.squid.recognizer.CodeRecognizer; + +public class Source { + + private List<Line> lines = new ArrayList<Line>(); + private CodeRecognizer codeRecognizer; + private Set<Integer> noSonarTagLines = new HashSet<Integer>(); + + public Source(Reader reader, CodeRecognizer codeRecognizer, String... additionalSingleLineCommentFlag) { + this.codeRecognizer = codeRecognizer; + LinesFactory linesFactory = new LinesFactory(reader, additionalSingleLineCommentFlag); + lines = linesFactory.getLines(); + processLines(); + } + + public Source(String[] stringLines, CodeRecognizer codeRecognizer) { + this(new StringArrayReader(stringLines), codeRecognizer); + } + + private void processLines() { + for (Line line : lines) { + computeBlankLine(line); + computeHeaderCommentLine(line); + computeCommentLine(line); + computeCommentBlankLine(line); + computeLineOfCode(line); + computeNoSonarTag(line); + line.deleteLineContent(); + } + } + + private void computeNoSonarTag(Line line) { + if (line.isThereNoSonarTag()) { + noSonarTagLines.add(line.getLineIndex()); + } + } + + private void computeLineOfCode(Line line) { + if (line.isThereCode()) { + line.setMeasure(Metric.LINES_OF_CODE, 1); + } + } + + private void computeHeaderCommentLine(Line line) { + if (line.isThereComment() && !line.isThereBlankComment() && line.isThereLicenseHeaderComment()) { + line.setMeasure(Metric.HEADER_COMMENT_LINES, 1); + } + } + + private void computeCommentLine(Line line) { + if (line.isThereComment() && !line.isThereBlankComment()) { + if (line.isThereJavadoc() || line.isThereLicenseHeaderComment()) { + line.setMeasure(Metric.COMMENT_LINES, 1); + return; + } + + boolean isCommentedOutCode = codeRecognizer.isLineOfCode(line.getComment()); + if (!isCommentedOutCode) { + line.setMeasure(Metric.COMMENT_LINES, 1); + } else { + line.setMeasure(Metric.COMMENTED_OUT_CODE_LINES, 1); + } + } + } + + private void computeBlankLine(Line line) { + if (line.isBlank()) { + line.setMeasure(Metric.BLANK_LINES, 1); + } + } + + private void computeCommentBlankLine(Line line) { + if (line.isThereBlankComment()) { + line.setMeasure(Metric.COMMENT_BLANK_LINES, 1); + } + } + + public int getMeasure(Metric metric) { + return getMeasure(metric, 1, lines.size()); + } + + public int getMeasure(Metric metric, int fromLine, int toLine) { + if (toLine > lines.size()) { + throw new IllegalStateException("There are only " + lines.size() + " lines in the file and you're trying to reach line " + toLine); + } + if (fromLine < 1) { + throw new IllegalStateException("Line index starts from 1 and not from " + fromLine); + } + + int measure = 0; + for (int index = fromLine; index < toLine + 1; index++) { + measure += lines.get(index - 1).getInt(metric); + } + return measure; + } + + public Set<Integer> getNoSonarTagLines() { + return noSonarTagLines; + } +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/text/StringArrayReader.java b/sonar-squid/src/main/java/org/sonar/squid/text/StringArrayReader.java new file mode 100644 index 00000000000..1c923d0adc7 --- /dev/null +++ b/sonar-squid/src/main/java/org/sonar/squid/text/StringArrayReader.java @@ -0,0 +1,96 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.squid.text; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; + +public class StringArrayReader extends Reader { + + private final StringReader stringReader; + + enum EndOfLineDelimiter { + LF, CR_PLUS_LF, CR + } + + public StringArrayReader(String[] lines) { + this(lines, EndOfLineDelimiter.LF); + } + + public StringArrayReader(String[] lines, EndOfLineDelimiter endOfLineDelimiter) { + if (lines == null) { + throw new IllegalStateException("lines object can't be null."); + } + String content = convertArrayToStringAndAppendEndOfLine(lines, endOfLineDelimiter); + stringReader = new StringReader(content); + } + + private String convertArrayToStringAndAppendEndOfLine(String[] lines, EndOfLineDelimiter endOfLineDelimiter) { + StringBuilder content = new StringBuilder(); + for (int i = 0; i < lines.length; i++) { + content.append(lines[i]); + if (i != (lines.length - 1)) { + switch (endOfLineDelimiter) { + case LF: + content.append('\n'); + break; + case CR: + content.append('\r'); + break; + case CR_PLUS_LF: + content.append("\r\n"); + break; + } + } + } + return content.toString(); + } + + @Override + public void close() throws IOException { + stringReader.close(); + } + + @Override + public boolean ready() throws IOException { + return stringReader.ready(); + } + + @Override + public boolean markSupported() { + return stringReader.markSupported(); + } + + @Override + public void mark(int readAheadLimit) throws IOException { + stringReader.mark(readAheadLimit); + } + + @Override + public void reset() throws IOException { + stringReader.reset(); + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + return stringReader.read(cbuf, off, len); + } +} |