@Override public DefaultSignificantCode addRange(TextRange range) { Preconditions.checkState(this.inputFile != null, "addRange() should be called after on()"); int line = range.start().line(); Preconditions.checkArgument(line == range.end().line(), "Ranges of significant code must be located in a single line"); Preconditions.checkState(!significantCodePerLine.containsKey(line), "Significant code was already reported for line '%s'. Can only report once per line.", line); significantCodePerLine.put(line, range); return this; }
@Override public NewSymbol newReference(TextRange range) { requireNonNull(range, "Provided range is null"); Preconditions.checkArgument(!declaration.overlap(range), "Overlapping symbol declaration and reference for symbol at %s", declaration); references.add(range); return this; }
private static void createIssues(InputFile file, SensorContext context, String repo) { RuleKey ruleKey = RuleKey.of(repo, RULE_KEY); for (int line = 1; line <= file.lines(); line++) { TextRange text = file.selectLine(line); // do not count empty lines, which can be a pain with end-of-file return if (text.end().lineOffset() == 0) { continue; } NewIssue newIssue = context.newIssue(); newIssue .forRule(ruleKey) .at(newIssue.newLocation() .on(file) .at(text) .message("This bug issue is generated on each line")) .save(); } }
private static boolean isOdd(FilterableIssue issue) { TextRange textRange = issue.textRange(); return textRange != null && textRange.start().line() % 2 == 1; } }
@Override public Integer getEndLine() { return textRange != null ? textRange.end().line() : null; }
private static boolean noSonar(DefaultInputComponent inputComponent, Issue issue) { TextRange textRange = issue.primaryLocation().textRange(); return inputComponent.isFile() && textRange != null && ((DefaultInputFile) inputComponent).hasNoSonarAt(textRange.start().line()) && !StringUtils.containsIgnoreCase(issue.ruleKey().rule(), "nosonar"); }
@Override public Integer getEndLineOffset() { return textRange != null ? textRange.end().lineOffset() : null; }
@Test public void testRangeOverlap() { Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16); DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata)); // Don't fail assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)))).isTrue(); assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 2)))).isTrue(); assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 1), file.newPointer(1, 2)))).isFalse(); assertThat(file.newRange(file.newPointer(1, 2), file.newPointer(1, 3)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 2)))).isFalse(); } }
@Test public void build_file_issue() { SensorStorage storage = mock(SensorStorage.class); DefaultExternalIssue issue = new DefaultExternalIssue(project, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1)) .message("Wrong way!")) .forRule(RuleKey.of("repo", "rule")) .remediationEffortMinutes(10l) .type(RuleType.BUG) .severity(Severity.BLOCKER); assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile); assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_repo", "rule")); assertThat(issue.engineId()).isEqualTo("repo"); assertThat(issue.ruleId()).isEqualTo("rule"); assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1); assertThat(issue.remediationEffort()).isEqualTo(10l); assertThat(issue.type()).isEqualTo(RuleType.BUG); assertThat(issue.severity()).isEqualTo(Severity.BLOCKER); assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!"); issue.save(); verify(storage).store(issue); }
private static void createIssues(InputFile file, SensorContext context, String repo) { RuleKey ruleKey = RuleKey.of(repo, RULE_KEY); for (int line = 1; line <= file.lines(); line++) { TextRange text = file.selectLine(line); // do not count empty lines, which can be a pain with end-of-file return if (text.end().lineOffset() == 0) { continue; } NewIssue newIssue = context.newIssue(); newIssue .forRule(ruleKey) .at(newIssue.newLocation() .on(file) .at(text) .message("This bug issue is generated on each line")) .save(); } }
@Override public NewSymbol newReference(TextRange range) { requireNonNull(range, "Provided range is null"); Preconditions.checkArgument(!declaration.overlap(range), "Overlapping symbol declaration and reference for symbol at %s", declaration); references.add(range); return this; }
private void checkOverlappingBoundaries() { if (syntaxHighlightingRules.size() > 1) { Iterator<SyntaxHighlightingRule> it = syntaxHighlightingRules.iterator(); SyntaxHighlightingRule previous = it.next(); while (it.hasNext()) { SyntaxHighlightingRule current = it.next(); if (previous.range().end().compareTo(current.range().start()) > 0 && (previous.range().end().compareTo(current.range().end()) < 0)) { String errorMsg = String.format("Cannot register highlighting rule for characters at %s as it " + "overlaps at least one existing rule", current.range()); throw new IllegalStateException(errorMsg); } previous = current; } } }
@Test public void build_file_issue() { SensorStorage storage = mock(SensorStorage.class); DefaultIssue issue = new DefaultIssue(project, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1)) .message("Wrong way!")) .forRule(RuleKey.of("repo", "rule")) .gap(10.0); assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile); assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule")); assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1); assertThat(issue.gap()).isEqualTo(10.0); assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!"); issue.save(); verify(storage).store(issue); }
} else { TextRange range = targetFile.selectLine(lineNumber); if (IS_WINDOWS && (getContext().runtime().getProduct() == SonarProduct.SONARLINT) && (range.end().lineOffset() > 1)) { location.at(targetFile.newRange(lineNumber, 0, lineNumber, range.end().lineOffset() - 1)); } else { location.at(range);
@Override public void newReference(Symbol symbol, int fromOffset, int toOffset) { if (!referencesBySymbol.containsKey(symbol)) { throw new UnsupportedOperationException("Cannot add reference to a symbol in another file"); } TextRange referenceRange = inputFile.newRange(fromOffset, toOffset); if (referenceRange.overlap(((DefaultSymbol) symbol).range())) { throw new UnsupportedOperationException("Cannot add reference (" + fromOffset + ") overlapping " + symbol + " in " + inputFile.key()); } referencesBySymbol.get(symbol).add(referenceRange); }
/** * Return list of symbol references ranges for the symbol at a given position in a file. * * @param componentKey Key of the file like 'myProjectKey:src/foo.php' * @param line Line you want to query * @param lineOffset Offset you want to query. * @return List of references for the symbol (potentially empty) or null if there is no symbol at this position. */ @CheckForNull public Collection<TextRange> referencesForSymbolAt(String componentKey, int line, int lineOffset) { DefaultSymbolTable symbolTable = sensorStorage.symbolsPerComponent.get(componentKey); if (symbolTable == null) { return null; } DefaultTextPointer location = new DefaultTextPointer(line, lineOffset); for (Map.Entry<TextRange, Set<TextRange>> symbol : symbolTable.getReferencesBySymbol().entrySet()) { if (symbol.getKey().start().compareTo(location) <= 0 && symbol.getKey().end().compareTo(location) > 0) { return symbol.getValue(); } } return null; }
@Test public void checkValidRange() { Metadata metadata = new FileMetadata().readMetadata(new StringReader("bla bla a\nabcde")); DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata)); assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 1)).start().line()).isEqualTo(1); // Don't fail file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)); file.newRange(file.newPointer(1, 0), file.newPointer(1, 9)); file.newRange(file.newPointer(1, 0), file.newPointer(2, 0)); assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 5))).isEqualTo(file.newRange(0, 15)); try { file.newRange(file.newPointer(1, 0), file.newPointer(1, 0)); fail(); } catch (Exception e) { assertThat(e).hasMessage("Start pointer [line=1, lineOffset=0] should be before end pointer [line=1, lineOffset=0]"); } try { file.newRange(file.newPointer(1, 0), file.newPointer(1, 10)); fail(); } catch (Exception e) { assertThat(e).hasMessage("10 is not a valid line offset for pointer. File src/Foo.php has 9 character(s) at line 1"); } }