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    }