Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
clang-tools-extra/clangd/Diagnostics.cpp
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) || | ||||
return false; | return false; | ||||
return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd()); | return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd()); | ||||
} | } | ||||
// Clang diags have a location (shown as ^) and 0 or more ranges (~~~~). | // Clang diags have a location (shown as ^) and 0 or more ranges (~~~~). | ||||
// LSP needs a single range. | // LSP needs a single range. | ||||
Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) { | Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) { | ||||
auto &M = D.getSourceManager(); | auto &M = D.getSourceManager(); | ||||
auto PatchedRange = [&M](CharSourceRange &R) { | |||||
R.setBegin(translatePreamblePatchLocation(R.getBegin(), M)); | |||||
sammccall: I think we answered this in the negative? | |||||
R.setEnd(translatePreamblePatchLocation(R.getEnd(), M)); | |||||
return R; | |||||
}; | |||||
auto Loc = M.getFileLoc(D.getLocation()); | auto Loc = M.getFileLoc(D.getLocation()); | ||||
for (const auto &CR : D.getRanges()) { | for (const auto &CR : D.getRanges()) { | ||||
auto R = Lexer::makeFileCharRange(CR, M, L); | auto R = Lexer::makeFileCharRange(CR, M, L); | ||||
if (locationInRange(Loc, R, M)) | if (locationInRange(Loc, R, M)) | ||||
return halfOpenToRange(M, R); | return halfOpenToRange(M, PatchedRange(R)); | ||||
} | } | ||||
// The range may be given as a fixit hint instead. | // The range may be given as a fixit hint instead. | ||||
for (const auto &F : D.getFixItHints()) { | for (const auto &F : D.getFixItHints()) { | ||||
auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L); | auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L); | ||||
if (locationInRange(Loc, R, M)) | if (locationInRange(Loc, R, M)) | ||||
return halfOpenToRange(M, R); | return halfOpenToRange(M, PatchedRange(R)); | ||||
} | } | ||||
// If the token at the location is not a comment, we use the token. | // 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 | // If we can't get the token at the location, fall back to using the location | ||||
auto R = CharSourceRange::getCharRange(Loc); | auto R = CharSourceRange::getCharRange(Loc); | ||||
Token Tok; | 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()); | R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc()); | ||||
} | } | ||||
return halfOpenToRange(M, R); | return halfOpenToRange(M, PatchedRange(R)); | ||||
} | } | ||||
// Try to find a location in the main-file to report the diagnostic D. | // Try to find a location in the main-file to report the diagnostic D. | ||||
// Returns a description like "in included file", or nullptr on failure. | // Returns a description like "in included file", or nullptr on failure. | ||||
const char *getMainFileRange(const Diag &D, const SourceManager &SM, | const char *getMainFileRange(const Diag &D, const SourceManager &SM, | ||||
SourceLocation DiagLoc, Range &R) { | SourceLocation DiagLoc, Range &R) { | ||||
// Look for a note in the main file indicating template instantiation. | // Look for a note in the main file indicating template instantiation. | ||||
for (const auto &N : D.Notes) { | for (const auto &N : D.Notes) { | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | bool tryMoveToMainFile(Diag &D, FullSourceLoc DiagLoc) { | ||||
D.File = SM.getFileEntryRefForID(SM.getMainFileID())->getName().str(); | D.File = SM.getFileEntryRefForID(SM.getMainFileID())->getName().str(); | ||||
D.Range = std::move(R); | D.Range = std::move(R); | ||||
D.InsideMainFile = true; | D.InsideMainFile = true; | ||||
// Update message to mention original file. | // Update message to mention original file. | ||||
D.Message = llvm::formatv("{0}: {1}", Prefix, D.Message); | D.Message = llvm::formatv("{0}: {1}", Prefix, D.Message); | ||||
return true; | return true; | ||||
} | } | ||||
bool isInsideMainFile(const clang::Diagnostic &D) { | |||||
if (!D.hasSourceManager()) | |||||
return false; | |||||
return clangd::isInsideMainFile(D.getLocation(), D.getSourceManager()); | |||||
} | |||||
bool isNote(DiagnosticsEngine::Level L) { | bool isNote(DiagnosticsEngine::Level L) { | ||||
return L == DiagnosticsEngine::Note || L == DiagnosticsEngine::Remark; | return L == DiagnosticsEngine::Note || L == DiagnosticsEngine::Remark; | ||||
} | } | ||||
llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) { | llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) { | ||||
switch (Lvl) { | switch (Lvl) { | ||||
case DiagnosticsEngine::Ignored: | case DiagnosticsEngine::Ignored: | ||||
return "ignored"; | return "ignored"; | ||||
▲ Show 20 Lines • Show All 477 Lines • ▼ Show 20 Lines | if (!LangOpts || !Info.hasSourceManager()) { | ||||
return; | return; | ||||
} | } | ||||
SourceManager &SM = Info.getSourceManager(); | SourceManager &SM = Info.getSourceManager(); | ||||
auto FillDiagBase = [&](DiagBase &D) { | auto FillDiagBase = [&](DiagBase &D) { | ||||
fillNonLocationData(DiagLevel, Info, D); | fillNonLocationData(DiagLevel, Info, D); | ||||
D.InsideMainFile = isInsideMainFile(Info); | SourceLocation PatchLoc = | ||||
translatePreamblePatchLocation(Info.getLocation(), SM); | |||||
D.InsideMainFile = isInsideMainFile(PatchLoc, SM); | |||||
PLoc is a confusing name for something that interacts with but is not a PresumedLoc I'd prefer avoiding auto here, too sammccall: PLoc is a confusing name for something that interacts with but is not a PresumedLoc
I'd prefer… | |||||
D.Range = diagnosticRange(Info, *LangOpts); | D.Range = diagnosticRange(Info, *LangOpts); | ||||
D.File = std::string(SM.getFilename(Info.getLocation())); | auto FID = SM.getFileID(Info.getLocation()); | ||||
D.AbsFile = getCanonicalPath( | if (auto *FE = SM.getFileEntryForID(FID)) { | ||||
SM.getFileEntryForID(SM.getFileID(Info.getLocation())), SM); | D.File = FE->getName().str(); | ||||
D.AbsFile = getCanonicalPath(FE, SM); | |||||
} | |||||
D.ID = Info.getID(); | D.ID = Info.getID(); | ||||
return D; | return D; | ||||
}; | }; | ||||
auto AddFix = [&](bool SyntheticMessage) -> bool { | auto AddFix = [&](bool SyntheticMessage) -> bool { | ||||
assert(!Info.getFixItHints().empty() && | assert(!Info.getFixItHints().empty() && | ||||
"diagnostic does not have attached fix-its"); | "diagnostic does not have attached fix-its"); | ||||
// No point in generating fixes, if the diagnostic is for a different file. | // No point in generating fixes, if the diagnostic is for a different file. | ||||
▲ Show 20 Lines • Show All 220 Lines • Show Last 20 Lines |
I think we answered this in the negative?