001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.squid.text;
021
022 import com.google.common.annotations.Beta;
023 import org.sonar.squid.measures.Metric;
024 import org.sonar.squid.recognizer.CodeRecognizer;
025
026 import java.io.Reader;
027 import java.util.ArrayList;
028 import java.util.HashSet;
029 import java.util.List;
030 import java.util.Set;
031
032 public class Source {
033
034 private List<Line> lines = new ArrayList<Line>();
035 private CodeRecognizer codeRecognizer;
036 private Set<Integer> noSonarTagLines = new HashSet<Integer>();
037
038 public Source(Reader reader, CodeRecognizer codeRecognizer, String... additionalSingleLineCommentFlag) {
039 this.codeRecognizer = codeRecognizer;
040 LinesFactory linesFactory = new LinesFactory(reader, additionalSingleLineCommentFlag);
041 lines = linesFactory.getLines();
042 processLines();
043 }
044
045 public Source(String[] stringLines, CodeRecognizer codeRecognizer) {
046 this(new StringArrayReader(stringLines), codeRecognizer);
047 }
048
049 private void processLines() {
050 for (Line line : lines) {
051 computeBlankLine(line);
052 computeHeaderCommentLine(line);
053 computeCommentLine(line);
054 computeCommentBlankLine(line);
055 computeLineOfCode(line);
056 computeNoSonarTag(line);
057 line.deleteLineContent();
058 }
059 }
060
061 private void computeNoSonarTag(Line line) {
062 if (line.isThereNoSonarTag()) {
063 noSonarTagLines.add(line.getLineIndex());
064 }
065 }
066
067 private void computeLineOfCode(Line line) {
068 if (line.isThereCode()) {
069 line.setMeasure(Metric.LINES_OF_CODE, 1);
070 }
071 }
072
073 private void computeHeaderCommentLine(Line line) {
074 if (line.isThereComment() && !line.isThereBlankComment() && line.isThereLicenseHeaderComment()) {
075 line.setMeasure(Metric.HEADER_COMMENT_LINES, 1);
076 }
077 }
078
079 private void computeCommentLine(Line line) {
080 if (line.isThereComment() && !line.isThereBlankComment()) {
081 if (line.isThereJavadoc() || line.isThereLicenseHeaderComment()) {
082 line.setMeasure(Metric.COMMENT_LINES, 1);
083 return;
084 }
085
086 boolean isCommentedOutCode = codeRecognizer.isLineOfCode(line.getComment());
087 if (!isCommentedOutCode) {
088 line.setMeasure(Metric.COMMENT_LINES, 1);
089 } else {
090 line.setMeasure(Metric.COMMENTED_OUT_CODE_LINES, 1);
091 }
092 }
093 }
094
095 private void computeBlankLine(Line line) {
096 if (line.isBlank()) {
097 line.setMeasure(Metric.BLANK_LINES, 1);
098 }
099 }
100
101 private void computeCommentBlankLine(Line line) {
102 if (line.isThereBlankComment()) {
103 line.setMeasure(Metric.COMMENT_BLANK_LINES, 1);
104 }
105 }
106
107 public int getMeasure(Metric metric) {
108 return getMeasure(metric, 1, lines.size());
109 }
110
111 /**
112 * Numbering of lines starts from 1.
113 */
114 public int getMeasure(Metric metric, int fromLine, int toLine) {
115 if (toLine > lines.size()) {
116 throw new IllegalStateException("There are only " + lines.size() + " lines in the file and you're trying to reach line " + toLine);
117 }
118 if (fromLine < 1) {
119 throw new IllegalStateException("Line index starts from 1 and not from " + fromLine);
120 }
121
122 int measure = 0;
123 for (int index = fromLine; index < toLine + 1; index++) {
124 measure += lines.get(index - 1).getInt(metric);
125 }
126 return measure;
127 }
128
129 public Set<Integer> getNoSonarTagLines() {
130 return noSonarTagLines;
131 }
132
133 /**
134 * @since 2.14
135 */
136 @Beta
137 public int getNumberOfLines() {
138 return lines.size();
139 }
140
141 }