gt:       for (int i = 0; i < lines.length; i++) {
context: /*
   * SonarQube Java
   * Copyright (C) 2012-2017 SonarSource SA
   * mailto:info AT sonarsource DOT com
   *
   * This program 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.
   *
   * This program 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 this program; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   */
  package org.sonar.java.ast.visitors;
  
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.Lists;
  import org.sonar.api.measures.CoreMetrics;
  import org.sonar.api.measures.FileLinesContext;
  import org.sonar.java.SonarComponents;
  import org.sonar.java.cfg.CFG;
  import org.sonar.java.model.ModifiersUtils;
  import org.sonar.plugins.java.api.JavaFileScannerContext;
  import org.sonar.plugins.java.api.tree.BlockTree;
  import org.sonar.plugins.java.api.tree.ExpressionTree;
  import org.sonar.plugins.java.api.tree.LambdaExpressionTree;
  import org.sonar.plugins.java.api.tree.MethodTree;
  import org.sonar.plugins.java.api.tree.Modifier;
  import org.sonar.plugins.java.api.tree.NewClassTree;
  import org.sonar.plugins.java.api.tree.SyntaxToken;
  import org.sonar.plugins.java.api.tree.SyntaxTrivia;
  import org.sonar.plugins.java.api.tree.Tree;
  import org.sonar.plugins.java.api.tree.TypeTree;
  import org.sonar.plugins.java.api.tree.VariableTree;
  
  import java.io.File;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  import static org.sonar.plugins.java.api.tree.Tree.Kind.BLOCK;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.BOOLEAN_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.CATCH;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.CHAR_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.CONSTRUCTOR;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.DOUBLE_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.DO_STATEMENT;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.FLOAT_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.FOR_EACH_STATEMENT;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.FOR_STATEMENT;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.INITIALIZER;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.INT_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.LAMBDA_EXPRESSION;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.LONG_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.METHOD;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.NEW_CLASS;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.NULL_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.STATIC_INITIALIZER;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.STRING_LITERAL;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.TOKEN;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.TRY_STATEMENT;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.VARIABLE;
  import static org.sonar.plugins.java.api.tree.Tree.Kind.WHILE_STATEMENT;
  
  /**
   * Saves information about lines directly into Sonar by using {@link FileLinesContext}.
   */
  public class FileLinesVisitor extends SubscriptionVisitor {
  
    private final SonarComponents sonarComponents;
    private final Set<Integer> linesOfCode = new HashSet<>();
    private final Set<Integer> linesOfComments = new HashSet<>();
    private final Set<Integer> executableLines = new HashSet<>();
  
    public FileLinesVisitor(SonarComponents sonarComponents) {
      this.sonarComponents = sonarComponents;
    }
  
    @Override
    public List<Tree.Kind> nodesToVisit() {
      if(sonarComponents.isSQGreaterThan62()) {
        return ImmutableList.of(TOKEN,
          METHOD, CONSTRUCTOR,
          INITIALIZER, STATIC_INITIALIZER,
          VARIABLE,
          FOR_EACH_STATEMENT, FOR_STATEMENT, WHILE_STATEMENT, DO_STATEMENT,
          LAMBDA_EXPRESSION);
      }
      return ImmutableList.of(TOKEN);
    }
  
    @Override
    public void scanFile(JavaFileScannerContext context) {
      super.scanFile(context);
      File currentFile = context.getFile();
      FileLinesContext fileLinesContext = sonarComponents.fileLinesContextFor(currentFile);
      int fileLength = sonarComponents.fileLength(currentFile);
      for (int line = 1; line <= fileLength; line++) {
        fileLinesContext.setIntValue(CoreMetrics.NCLOC_DATA_KEY, line, linesOfCode.contains(line) ? 1 : 0);
        fileLinesContext.setIntValue(CoreMetrics.COMMENT_LINES_DATA_KEY, line, linesOfComments.contains(line) ? 1 : 0);
        if(sonarComponents.isSQGreaterThan62()) {
          fileLinesContext.setIntValue(CoreMetrics.EXECUTABLE_LINES_DATA_KEY, line, executableLines.contains(line) ? 1 : 0);
        }
      }
      fileLinesContext.save();
  
      linesOfCode.clear();
      linesOfComments.clear();
      executableLines.clear();
    }
  
    @Override
    public void visitNode(Tree tree) {
      List<? extends Tree> trees = Collections.emptyList();
      switch (tree.kind()) {
        case INITIALIZER:
        case STATIC_INITIALIZER:
          trees = ((BlockTree) tree).body();
          break;
        case VARIABLE:
          trees = visitVariable((VariableTree) tree);
          break;
        case LAMBDA_EXPRESSION:
          trees = visitLambda((LambdaExpressionTree) tree);
          break;
        case METHOD:
        case CONSTRUCTOR:
          trees = visitMethod((MethodTree) tree);
          break;
        case FOR_STATEMENT:
        case FOR_EACH_STATEMENT:
        case WHILE_STATEMENT:
        case DO_STATEMENT:
          executableLines.add(tree.lastToken().line());
          break;
        default:
          // Do nothing particular
      }
      computeExecutableLines(trees);
    }
  
    private List<? extends Tree> visitVariable(VariableTree variableTree) {
      ExpressionTree initializer = variableTree.initializer();
      if(initializer != null && !isConstant(variableTree)) {
        return Lists.newArrayList(initializer);
      }
      if(variableTree.parent().is(CATCH)) {
        // catch variable are counted as executable lines
        new ExecutableLinesTokenVisitor().scanTree(variableTree);
      }
      return Collections.emptyList();
    }
  
    private static List<? extends Tree> visitLambda(LambdaExpressionTree lambda) {
      Tree body = lambda.body();
      if(body.is(BLOCK)) {
        return ((BlockTree) body).body();
      }
      return Lists.newArrayList(body);
    }
  
    private List<? extends Tree> visitMethod(MethodTree tree) {
      BlockTree methodBody = tree.block();
      if(methodBody != null) {
        // get the last
        TypeTree returnType = tree.returnType();
        if(returnType == null || "void".equals(returnType.firstToken().text())) {
          executableLines.add(methodBody.closeBraceToken().line());
        }
        return methodBody.body();
      }
      return Collections.emptyList();
    }
  
    private void computeExecutableLines(List<? extends Tree> trees) {
      if(trees.isEmpty()) {
        return;
      }
      // rely on cfg to get every instructions and get most of the token.
      CFG cfg = CFG.buildCFG(trees);
      cfg.blocks()
        .stream()
        .flatMap(b->b.elements().stream())
        .forEach(
          t -> {
            if (t.is(NEW_CLASS)) {
              NewClassTree newClassTree = (NewClassTree) t;
              new ExecutableLinesTokenVisitor().scanTree(newClassTree.identifier());
              executableLines.add(newClassTree.newKeyword().line());
            } else if (t.is(TRY_STATEMENT)) {
              // add last token of try statements
              executableLines.add(t.lastToken().line());
            } else {
              executableLines.add(t.firstToken().line());
            }
          }
        );
    }
  
    @Override
    public void visitToken(SyntaxToken syntaxToken) {
      linesOfCode.add(syntaxToken.line());
      for (SyntaxTrivia trivia : syntaxToken.trivias()) {
        int baseLine = trivia.startLine();
        String[] lines = trivia.comment().split("(\r)?\n|\r", -1);
  