// Clang diags have a location (shown as ^) and 0 or more ranges (~~~~).
// LSP needs a single range.
-Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
+std::optional<Range> diagnosticRange(const clang::Diagnostic &D,
+ const LangOptions &L) {
auto &M = D.getSourceManager();
auto PatchedRange = [&M](CharSourceRange &R) {
R.setBegin(translatePreamblePatchLocation(R.getBegin(), M));
if (locationInRange(Loc, R, M))
return halfOpenToRange(M, PatchedRange(R));
}
+ // Source locations from stale preambles might become OOB.
+ // FIXME: These diagnostics might point to wrong locations even when they're
+ // not OOB.
+ auto [FID, Offset] = M.getDecomposedLoc(Loc);
+ if (Offset > M.getBufferData(FID).size())
+ return std::nullopt;
// If the token at the location is not a comment, we use the token.
// If we can't get the token at the location, fall back to using the location
auto R = CharSourceRange::getCharRange(Loc);
Token Tok;
- if (!Lexer::getRawToken(Loc, Tok, M, L, true) && Tok.isNot(tok::comment)) {
+ if (!Lexer::getRawToken(Loc, Tok, M, L, true) && Tok.isNot(tok::comment))
R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc());
- }
return halfOpenToRange(M, PatchedRange(R));
}
SourceLocation PatchLoc =
translatePreamblePatchLocation(Info.getLocation(), SM);
D.InsideMainFile = isInsideMainFile(PatchLoc, SM);
- D.Range = diagnosticRange(Info, *LangOpts);
+ if (auto DRange = diagnosticRange(Info, *LangOpts))
+ D.Range = *DRange;
+ else
+ D.Severity = DiagnosticsEngine::Ignored;
auto FID = SM.getFileID(Info.getLocation());
if (const auto FE = SM.getFileEntryRefForID(FID)) {
D.File = FE->getName().str();
auto AST = createPatchedAST(Code.code(), NewCode.code());
EXPECT_THAT(*AST->getDiagnostics(), IsEmpty());
}
+ {
+ Annotations Code(R"(
+#ifndef FOO
+#define FOO
+void foo();
+#endif)");
+ // This code will emit a diagnostic for unterminated #ifndef (as stale
+ // preamble has the conditional but main file doesn't terminate it).
+ // We shouldn't emit any diagnotiscs (and shouldn't crash).
+ Annotations NewCode("");
+ auto AST = createPatchedAST(Code.code(), NewCode.code());
+ EXPECT_THAT(*AST->getDiagnostics(), IsEmpty());
+ }
+ {
+ Annotations Code(R"(
+#ifndef FOO
+#define FOO
+void foo();
+#endif)");
+ // This code will emit a diagnostic for unterminated #ifndef (as stale
+ // preamble has the conditional but main file doesn't terminate it).
+ // We shouldn't emit any diagnotiscs (and shouldn't crash).
+ // FIXME: Patch/ignore diagnostics in such cases.
+ Annotations NewCode(R"(
+i[[nt]] xyz;
+ )");
+ auto AST = createPatchedAST(Code.code(), NewCode.code());
+ EXPECT_THAT(
+ *AST->getDiagnostics(),
+ ElementsAre(Diag(NewCode.range(), "pp_unterminated_conditional")));
+ }
}
MATCHER_P2(Mark, Range, Text, "") {