|
| 1 | +#include "swift/extractor/invocation/CodeQLDiagnosticsConsumer.h" |
| 2 | +#include "swift/extractor/trap/TrapDomain.h" |
| 3 | +#include "swift/extractor/trap/generated/TrapEntries.h" |
| 4 | + |
| 5 | +#include <swift/AST/DiagnosticEngine.h> |
| 6 | +#include <swift/Basic/SourceManager.h> |
| 7 | +#include <llvm/ADT/SmallString.h> |
| 8 | +#include <llvm/Support/raw_ostream.h> |
| 9 | +#include <string> |
| 10 | + |
| 11 | +using namespace codeql; |
| 12 | + |
| 13 | +static int diagnosticsKind(const swift::DiagnosticInfo& diagInfo) { |
| 14 | + switch (diagInfo.Kind) { |
| 15 | + case swift::DiagnosticKind::Error: |
| 16 | + return 1; |
| 17 | + case swift::DiagnosticKind::Warning: |
| 18 | + return 2; |
| 19 | + |
| 20 | + case swift::DiagnosticKind::Note: |
| 21 | + return 3; |
| 22 | + |
| 23 | + case swift::DiagnosticKind::Remark: |
| 24 | + return 4; |
| 25 | + } |
| 26 | + return 0; |
| 27 | +} |
| 28 | + |
| 29 | +static std::filesystem::path getFilePath(std::string_view path) { |
| 30 | + // TODO: this needs more testing |
| 31 | + // TODO: check canonicalization of names on a case insensitive filesystems |
| 32 | + // TODO: make symlink resolution conditional on CODEQL_PRESERVE_SYMLINKS=true |
| 33 | + std::error_code ec; |
| 34 | + auto ret = std::filesystem::canonical(path, ec); |
| 35 | + if (ec) { |
| 36 | + std::cerr << "Cannot get real path: " << std::quoted(path) << ": " << ec.message() << "\n"; |
| 37 | + return {}; |
| 38 | + } |
| 39 | + return ret; |
| 40 | +} |
| 41 | + |
| 42 | +static void attachLocation(TrapDomain& trap, |
| 43 | + swift::SourceManager& sourceManager, |
| 44 | + const swift::DiagnosticInfo& diagInfo, |
| 45 | + DiagnosticsTrap& locatable) { |
| 46 | + auto loc = diagInfo.Loc; |
| 47 | + if (!loc.isValid()) { |
| 48 | + return; |
| 49 | + } |
| 50 | + auto filepath = getFilePath(sourceManager.getDisplayNameForLoc(loc)); |
| 51 | + FilesTrap file; |
| 52 | + file.id = trap.createLabel<FileTag>(); |
| 53 | + file.name = filepath; |
| 54 | + trap.emit(file); |
| 55 | + |
| 56 | + LocationsTrap location; |
| 57 | + location.id = trap.createLabel<LocationTag>(); |
| 58 | + location.file = file.id; |
| 59 | + std::tie(location.start_line, location.start_column) = |
| 60 | + sourceManager.getLineAndColumnInBuffer(loc); |
| 61 | + std::tie(location.end_line, location.end_column) = sourceManager.getLineAndColumnInBuffer(loc); |
| 62 | + trap.emit(location); |
| 63 | + trap.emit(LocatableLocationsTrap{locatable.id, location.id}); |
| 64 | +} |
| 65 | + |
| 66 | +void CodeQLDiagnosticsConsumer::handleDiagnostic(swift::SourceManager& sourceManager, |
| 67 | + const swift::DiagnosticInfo& diagInfo) { |
| 68 | + auto message = getDiagMessage(sourceManager, diagInfo); |
| 69 | + DiagnosticsTrap diag{}; |
| 70 | + diag.id = trap.createLabel<DiagnosticsTag>(); |
| 71 | + diag.kind = diagnosticsKind(diagInfo); |
| 72 | + diag.text = message; |
| 73 | + trap.emit(diag); |
| 74 | + attachLocation(trap, sourceManager, diagInfo, diag); |
| 75 | +} |
| 76 | + |
| 77 | +std::string CodeQLDiagnosticsConsumer::getDiagMessage(swift::SourceManager& sourceManager, |
| 78 | + const swift::DiagnosticInfo& diagInfo) { |
| 79 | + // Translate ranges. |
| 80 | + llvm::SmallVector<llvm::SMRange, 2> ranges; |
| 81 | + for (auto R : diagInfo.Ranges) |
| 82 | + ranges.push_back(getRawRange(sourceManager, R)); |
| 83 | + |
| 84 | + // Translate fix-its. |
| 85 | + llvm::SmallVector<llvm::SMFixIt, 2> fixIts; |
| 86 | + for (const swift::DiagnosticInfo::FixIt& F : diagInfo.FixIts) |
| 87 | + fixIts.push_back(getRawFixIt(sourceManager, F)); |
| 88 | + |
| 89 | + // Actually substitute the diagnostic arguments into the diagnostic text. |
| 90 | + llvm::SmallString<256> Text; |
| 91 | + { |
| 92 | + llvm::raw_svector_ostream Out(Text); |
| 93 | + swift::DiagnosticEngine::formatDiagnosticText(Out, diagInfo.FormatString, diagInfo.FormatArgs); |
| 94 | + } |
| 95 | + |
| 96 | + return Text.str().str(); |
| 97 | +} |
0 commit comments