예제 #1
0
  /** Create issue report according to issue list generated during SonarQube analysis. */
  public static SonarQubeIssuesReport extractIssueReport(
      ProjectIssues projectIssues, InputFileCache inputFileCache, File projectBaseDir) {
    SonarQubeIssuesReport result = new SonarQubeIssuesReport();

    for (Issue issue : projectIssues.issues()) {
      if (!issue.isNew()) {
        LOGGER.debug("Issue {} is not a new issue and so, not added to the report", issue.key());
      } else {
        String key = issue.key();
        String severity = issue.severity();
        String rule = issue.ruleKey().toString();
        String message = issue.message();

        int line = 0;
        if (issue.line() != null) {
          line = issue.line();
        }

        InputFile inputFile = inputFileCache.getInputFile(issue.componentKey());
        if (inputFile == null) {
          LOGGER.debug("Issue {} is not linked to a file, not added to the report", issue.key());
        } else {
          String path = new PathResolver().relativePath(projectBaseDir, inputFile.file());

          // Create the issue and Add to report
          SonarQubeIssue stashIssue = new SonarQubeIssue(key, severity, message, rule, path, line);
          result.add(stashIssue);
        }
      }
    }

    return result;
  }
예제 #2
0
  /**
   * Check if the xml file starts with a prolog "&lt?xml version="1.0" ?&gt" if so, check if there
   * is any characters prefixing it.
   */
  private void checkForCharactersBeforeProlog(FileSystem fileSystem) {
    try {
      int lineNb = 1;
      Pattern firstTagPattern = Pattern.compile("<[a-zA-Z?]+");
      boolean hasBOM = false;

      for (String line : Files.readLines(inputFile.file(), fileSystem.encoding())) {
        if (lineNb == 1 && line.startsWith(BOM_CHAR)) {
          hasBOM = true;
          characterDeltaForHighlight = -1;
        }

        Matcher m = firstTagPattern.matcher(line);
        if (m.find()) {
          int column = line.indexOf(m.group());

          if (XML_PROLOG_START_TAG.equals(m.group()) && !isFileBeginning(lineNb, column, hasBOM)) {
            hasCharsBeforeProlog = true;
          }
          break;
        }
        lineNb++;
      }

      if (hasCharsBeforeProlog) {
        processCharBeforePrologInFile(fileSystem, lineNb);
      }
    } catch (IOException e) {
      LOG.warn("Unable to analyse file {}", inputFile.absolutePath(), e);
    }
  }
 @VisibleForTesting
 protected void analyseFiles(
     SensorContext context,
     List<TreeVisitor> treeVisitors,
     Iterable<InputFile> inputFiles,
     ProgressReport progressReport) {
   boolean success = false;
   try {
     for (InputFile inputFile : inputFiles) {
       // check for cancellation of the analysis (by SonarQube or SonarLint). See SONARJS-761.
       if (context.getSonarQubeVersion().isGreaterThanOrEqual(V6_0) && context.isCancelled()) {
         throw new CancellationException(
             "Analysis interrupted because the SensorContext is in cancelled state");
       }
       if (!isExcluded(inputFile.file())) {
         analyse(context, inputFile, treeVisitors);
       }
       progressReport.nextFile();
     }
     success = true;
   } catch (CancellationException e) {
     // do not propagate the exception
     LOG.debug(e.toString());
   } finally {
     stopProgressReport(progressReport, success);
   }
 }
예제 #4
0
 public void finish() {
   progressReport.stop(count + "/" + total + " files analyzed");
   if (!allFilesToBlame.isEmpty()) {
     LOG.warn("Missing blame information for the following files:");
     for (InputFile f : allFilesToBlame) {
       LOG.warn("  * " + f.absolutePath());
     }
     LOG.warn("This may lead to missing/broken features in SonarQube");
   }
 }
예제 #5
0
 private static void validateLine(BlameLine line, int lineId, InputFile file) {
   Preconditions.checkArgument(
       StringUtils.isNotBlank(line.revision()),
       "Blame revision is blank for file %s at line %s",
       file.relativePath(),
       lineId);
   Preconditions.checkArgument(
       line.date() != null,
       "Blame date is null for file %s at line %s",
       file.relativePath(),
       lineId);
 }
예제 #6
0
  private static void validateMaxLine(Map<Integer, Integer> m, InputFile inputFile) {
    int maxLine = inputFile.lines();

    for (int l : m.keySet()) {
      if (l > maxLine) {
        throw new IllegalStateException(
            String.format(
                "Can't create measure for line %d for file '%s' with %d lines",
                l, inputFile.absolutePath(), maxLine));
      }
    }
  }
예제 #7
0
 private long getDevelopmentCost(DecoratorContext context) {
   InputFile file = fs.inputFile(fs.predicates().hasRelativePath(context.getResource().getKey()));
   if (file != null) {
     String language = file.language();
     return getMeasureValue(context, sqaleRatingSettings.getSizeMetric(language, metrics))
         * sqaleRatingSettings.getDevCost(language);
   } else {
     Collection<Measure> childrenMeasures =
         context.getChildrenMeasures(CoreMetrics.DEVELOPMENT_COST);
     Double sum = sum(childrenMeasures);
     return sum.longValue();
   }
 }
  private void scanFile(
      SensorContext sensorContext,
      InputFile inputFile,
      List<TreeVisitor> visitors,
      ScriptTree scriptTree) {
    JavaScriptVisitorContext context =
        new JavaScriptVisitorContext(scriptTree, inputFile.file(), sensorContext.settings());

    highlightSymbols(sensorContext.newSymbolTable().onFile(inputFile), context);

    List<Issue> fileIssues = new ArrayList<>();

    for (TreeVisitor visitor : visitors) {
      if (visitor instanceof CharsetAwareVisitor) {
        ((CharsetAwareVisitor) visitor).setCharset(fileSystem.encoding());
      }

      if (visitor instanceof JavaScriptCheck) {
        fileIssues.addAll(((JavaScriptCheck) visitor).scanFile(context));

      } else {
        visitor.scanTree(context);
      }
    }

    saveFileIssues(sensorContext, fileIssues, inputFile);
  }
  @Test
  public void should_register_tests() throws URISyntaxException {
    SensorContextTester context = SensorContextTester.create(new File(""));

    MutableTestCase testCase = mock(MutableTestCase.class);
    when(testCase.setDurationInMs(anyLong())).thenReturn(testCase);
    when(testCase.setStatus(any(TestCase.Status.class))).thenReturn(testCase);
    when(testCase.setMessage(anyString())).thenReturn(testCase);
    when(testCase.setStackTrace(anyString())).thenReturn(testCase);
    when(testCase.setType(anyString())).thenReturn(testCase);
    MutableTestPlan testPlan = mock(MutableTestPlan.class);
    when(testPlan.addTestCase(anyString())).thenReturn(testCase);
    when(perspectives.as(
            eq(MutableTestPlan.class),
            argThat(
                new ArgumentMatcher<InputFile>() {
                  @Override
                  public boolean matches(Object o) {
                    if (o instanceof InputFile) {
                      return ":ch.hortis.sonar.mvn.mc.MetricsCollectorRegistryTest"
                          .equals(((InputFile) o).key());
                    }
                    return false;
                  }
                })))
        .thenReturn(testPlan);

    parser.collect(context, getDir("multipleReports"), true);

    verify(testPlan).addTestCase("testGetUnKnownCollector");
    verify(testPlan).addTestCase("testGetJDependsCollector");
  }
  private void analyse(
      SensorContext sensorContext, InputFile inputFile, List<TreeVisitor> visitors) {
    ScriptTree scriptTree;

    try {
      scriptTree = (ScriptTree) parser.parse(new java.io.File(inputFile.absolutePath()));
      scanFile(sensorContext, inputFile, visitors, scriptTree);

    } catch (RecognitionException e) {
      checkInterrupted(e);
      LOG.error("Unable to parse file: " + inputFile.absolutePath());
      LOG.error(e.getMessage());
      processRecognitionException(e, sensorContext, inputFile);

    } catch (Exception e) {
      checkInterrupted(e);
      processException(e, sensorContext, inputFile);
      throw new AnalysisException("Unable to analyse file: " + inputFile.absolutePath(), e);
    }
  }
예제 #11
0
  public void validate(Measure<?> measure, InputFile inputFile) {
    Metric<?> metric = measure.getMetric();

    if (!isLineMetrics(metric)) {
      return;
    }

    Map<Integer, Integer> m = KeyValueFormat.parseIntInt(measure.getData());
    validatePositiveLine(m, inputFile.absolutePath());
    validateMaxLine(m, inputFile);
  }
예제 #12
0
 @Override
 public boolean accept(InputFile inputFile) {
   if (filters.length > 0) {
     DeprecatedContext context = new DeprecatedContext(inputFile);
     for (FileSystemFilter filter : filters) {
       if (!filter.accept(inputFile.file(), context)) {
         return false;
       }
     }
   }
   return true;
 }
예제 #13
0
 @Override
 public MutableTestCase setCoverageBlock(InputFile mainFile, List<Integer> lines) {
   Preconditions.checkArgument(
       mainFile.type() == Type.MAIN, "Test file can only cover a main file");
   DefaultInputFile coveredFile = (DefaultInputFile) mainFile;
   if (coverageBlocksByTestedFile.containsKey(coveredFile)) {
     throw new CoverageAlreadyExistsException(
         "The link between " + name() + " and " + coveredFile.key() + " already exists");
   }
   coverageBlocksByTestedFile.put(coveredFile, new DefaultCoverageBlock(this, coveredFile, lines));
   return this;
 }
예제 #14
0
  @Override
  public synchronized void blameResult(InputFile file, List<BlameLine> lines) {
    Preconditions.checkNotNull(file);
    Preconditions.checkNotNull(lines);
    Preconditions.checkArgument(
        allFilesToBlame.contains(file),
        "It was not expected to blame file %s",
        file.relativePath());

    if (lines.size() != file.lines()) {
      LOG.debug(
          "Ignoring blame result since provider returned {} blame lines but file {} has {} lines",
          lines.size(),
          file.relativePath(),
          file.lines());
      return;
    }

    BatchComponent batchComponent = componentCache.get(file);
    Builder scmBuilder = BatchReport.Changesets.newBuilder();
    scmBuilder.setComponentRef(batchComponent.batchId());
    Map<String, Integer> changesetsIdByRevision = new HashMap<>();

    int lineId = 1;
    for (BlameLine line : lines) {
      validateLine(line, lineId, file);
      Integer changesetId = changesetsIdByRevision.get(line.revision());
      if (changesetId == null) {
        addChangeset(scmBuilder, line);
        changesetId = scmBuilder.getChangesetCount() - 1;
        changesetsIdByRevision.put(line.revision(), changesetId);
      }
      scmBuilder.addChangesetIndexByLine(changesetId);
      lineId++;
    }
    writer.writeComponentChangesets(scmBuilder.build());
    allFilesToBlame.remove(file);
    count++;
    progressReport.message(count + "/" + total + " files analyzed");
  }
  private static void saveLineIssue(
      SensorContext sensorContext, InputFile inputFile, RuleKey ruleKey, LineIssue issue) {
    NewIssue newIssue = sensorContext.newIssue();

    NewIssueLocation primaryLocation =
        newIssue
            .newLocation()
            .message(issue.message())
            .on(inputFile)
            .at(inputFile.selectLine(issue.line()));

    saveIssue(newIssue, primaryLocation, ruleKey, issue);
  }
예제 #16
0
  /**
   * Create a temporary file without any character before the prolog and update the following
   * attributes in order to correctly report issues:
   *
   * <ul>
   *   <li>lineDeltaForIssue
   *   <li>file
   */
  private void processCharBeforePrologInFile(FileSystem fileSystem, int lineDelta) {
    try {
      String content = Files.toString(inputFile.file(), fileSystem.encoding());
      File tempFile = new File(fileSystem.workDir(), inputFile.file().getName());

      int index = content.indexOf(XML_PROLOG_START_TAG);
      Files.write(content.substring(index), tempFile, fileSystem.encoding());

      noCharBeforePrologFile = tempFile;

      if (index != -1) {
        characterDeltaForHighlight += index;
      }

      if (lineDelta > 1) {
        lineDeltaForIssue = lineDelta - 1;
      }

    } catch (IOException e) {
      LOG.warn("Unable to analyse file {}", inputFile.absolutePath(), e);
    }
  }
  private void processRecognitionException(
      RecognitionException e, SensorContext sensorContext, InputFile inputFile) {
    if (parsingErrorRuleKey != null) {
      NewIssue newIssue = sensorContext.newIssue();

      NewIssueLocation primaryLocation =
          newIssue
              .newLocation()
              .message(e.getMessage())
              .on(inputFile)
              .at(inputFile.selectLine(e.getLine()));

      newIssue.forRule(parsingErrorRuleKey).at(primaryLocation).save();
    }

    if (sensorContext.getSonarQubeVersion().isGreaterThanOrEqual(V6_0)) {
      sensorContext
          .newAnalysisError()
          .onFile(inputFile)
          .at(inputFile.newPointer(e.getLine(), 0))
          .message(e.getMessage())
          .save();
    }
  }
  private static NewIssueLocation newLocation(
      InputFile inputFile, NewIssue issue, IssueLocation location) {
    TextRange range =
        inputFile.newRange(
            location.startLine(),
            location.startLineOffset(),
            location.endLine(),
            location.endLineOffset());

    NewIssueLocation newLocation = issue.newLocation().on(inputFile).at(range);

    if (location.message() != null) {
      newLocation.message(location.message());
    }
    return newLocation;
  }
예제 #19
0
  @Override
  public void visitToken(Token token) {
    if (!token.isGeneratedCode()) {
      String text;
      if (ignoreIdentifiers && token.getType().equals(GenericTokenType.IDENTIFIER)) {
        text = "_I";
      } else if (ignoreLiterals && token.getType().equals(CxxTokenType.NUMBER)) {
        text = "_N";
      } else if (ignoreLiterals && token.getType().equals(CxxTokenType.STRING)) {
        text = "_S";
      } else if (ignoreLiterals && token.getType().equals(CxxTokenType.CHARACTER)) {
        text = "_C";
      } else if (token.getType().equals(GenericTokenType.EOF)) {
        return;
      } else {
        text = token.getValue();
      }

      try {
        TextRange range =
            inputFile.newRange(
                token.getLine(),
                token.getColumn(),
                token.getLine(),
                token.getColumn() + token.getValue().length());
        cpdTokens.addToken(range, text);
      } catch (Exception e) {
        // ignore range errors: parsing errors could lead to wrong location data
        LOG.debug(
            "CPD error in file '{}' at line:{}, column:{}",
            getContext().getFile().getAbsoluteFile(),
            token.getLine(),
            token.getColumn());
      }
    }
  }
예제 #20
0
 public String getFilePath() {
   return inputFile.absolutePath();
 }
예제 #21
0
 @Override
 public FileType type() {
   String type = inputFile.type().name();
   return FileType.valueOf(type);
 }
예제 #22
0
 @Override
 public String relativePath() {
   return inputFile.relativePath();
 }
예제 #23
0
 @Override
 public String canonicalPath() {
   return inputFile.absolutePath();
 }
예제 #24
0
 public File getIOFile() {
   return noCharBeforePrologFile != null ? noCharBeforePrologFile : inputFile.file();
 }
예제 #25
0
 @Override
 public boolean apply(InputFile f) {
   return type == f.type();
 }