/// \brief Computes the source location just past the end of the token at /// the given source location. If the location points at a macro, the whole /// macro expansion is skipped. SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc, SourceManager &SM, Preprocessor &PP) { if (loc.isMacroID()) loc = SM.getExpansionRange(loc).second; return PP.getLocForEndOfToken(loc); }
static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth, bool isKeyEvent = false) { Indent(o, indent) << "<dict>\n"; ++indent; Indent(o, indent) << "<key>kind</key><string>event</string>\n"; if (isKeyEvent) { Indent(o, indent) << "<key>key_event</key><true/>\n"; } // Output the location. FullSourceLoc L = P.getLocation().asLocation(); Indent(o, indent) << "<key>location</key>\n"; EmitLocation(o, SM, L, FM, indent); // Output the ranges (if any). ArrayRef<SourceRange> Ranges = P.getRanges(); if (!Ranges.empty()) { Indent(o, indent) << "<key>ranges</key>\n"; Indent(o, indent) << "<array>\n"; ++indent; for (auto &R : Ranges) EmitRange(o, SM, Lexer::getAsCharRange(SM.getExpansionRange(R), SM, LangOpts), FM, indent + 1); --indent; Indent(o, indent) << "</array>\n"; } // Output the call depth. Indent(o, indent) << "<key>depth</key>"; EmitInteger(o, depth) << '\n'; // Output the text. assert(!P.getString().empty()); Indent(o, indent) << "<key>extended_message</key>\n"; Indent(o, indent); EmitString(o, P.getString()) << '\n'; // Output the short text. // FIXME: Really use a short string. Indent(o, indent) << "<key>message</key>\n"; Indent(o, indent); EmitString(o, P.getString()) << '\n'; // Finish up. --indent; Indent(o, indent); o << "</dict>\n"; }
/// \brief Print out the file/line/column information and include trace. /// /// This method handlen the emission of the diagnostic location information. /// This includes extracting as much location information as is present for /// the diagnostic and printing it, as well as any include stack or source /// ranges necessary. void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, const SourceManager &SM) { if (PLoc.isInvalid()) { // At least print the file name if available: FileID FID = SM.getFileID(Loc); if (!FID.isInvalid()) { const FileEntry* FE = SM.getFileEntryForID(FID); if (FE && FE->getName()) { OS << FE->getName(); if (FE->getDevice() == 0 && FE->getInode() == 0 && FE->getFileMode() == 0) { // in PCH is a guess, but a good one: OS << " (in PCH)"; } OS << ": "; } } return; } unsigned LineNo = PLoc.getLine(); if (!DiagOpts->ShowLocation) return; if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); OS << PLoc.getFilename(); switch (DiagOpts->getFormat()) { case DiagnosticOptions::LFort: OS << ':' << LineNo; break; case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; case DiagnosticOptions::Vi: OS << " +" << LineNo; break; } if (DiagOpts->ShowColumn) // Compute the column number. if (unsigned ColNo = PLoc.getColumn()) { if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) { OS << ','; ColNo--; } else OS << ':'; OS << ColNo; } switch (DiagOpts->getFormat()) { case DiagnosticOptions::LFort: case DiagnosticOptions::Vi: OS << ':'; break; case DiagnosticOptions::Msvc: OS << ") : "; break; } if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { FileID CaretFileID = SM.getFileID(SM.getExpansionLoc(Loc)); bool PrintedRange = false; for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(), RE = Ranges.end(); RI != RE; ++RI) { // Ignore invalid ranges. if (!RI->isValid()) continue; SourceLocation B = SM.getExpansionLoc(RI->getBegin()); SourceLocation E = SM.getExpansionLoc(RI->getEnd()); // If the End location and the start location are the same and are a // macro location, then the range was something that came from a // macro expansion or _Pragma. If this is an object-like macro, the // best we can do is to highlight the range. If this is a // function-like macro, we'd also like to highlight the arguments. if (B == E && RI->getEnd().isMacroID()) E = SM.getExpansionRange(RI->getEnd()).second; std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); // If the start or end of the range is in another file, just discard // it. if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) continue; // Add in the length of the token, so that we cover multi-char // tokens. unsigned TokSize = 0; if (RI->isTokenRange()) TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts); OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' << SM.getLineNumber(EInfo.first, EInfo.second) << ':' << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}'; PrintedRange = true; } if (PrintedRange) OS << ':'; } OS << ' '; }
SourceLocation getExpansionEnd(SourceManager& sourceManager, const Decl* decl) { SourceLocation end = decl->getLocEnd(); if (end.isMacroID()) end = sourceManager.getExpansionRange(end).second; return end; }
SourceLocation getExpansionStart(SourceManager& sourceManager, const Decl* decl) { SourceLocation start = decl->getLocStart(); if (start.isMacroID()) start = sourceManager.getExpansionRange(start).first; return start; }
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. void TextDiagnostic::highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, const SourceColumnMap &map, std::string &CaretLine, const SourceManager &SM) { if (!R.isValid()) return; SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); SourceLocation End = SM.getExpansionLoc(R.getEnd()); // If the End location and the start location are the same and are a macro // location, then the range was something that came from a macro expansion // or _Pragma. If this is an object-like macro, the best we can do is to // highlight the range. If this is a function-like macro, we'd also like to // highlight the arguments. if (Begin == End && R.getEnd().isMacroID()) End = SM.getExpansionRange(R.getEnd()).second; unsigned StartLineNo = SM.getExpansionLineNumber(Begin); if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) return; // No intersection. unsigned EndLineNo = SM.getExpansionLineNumber(End); if (EndLineNo < LineNo || SM.getFileID(End) != FID) return; // No intersection. // Compute the column number of the start. unsigned StartColNo = 0; if (StartLineNo == LineNo) { StartColNo = SM.getExpansionColumnNumber(Begin); if (StartColNo) --StartColNo; // Zero base the col #. } // Compute the column number of the end. unsigned EndColNo = map.getSourceLine().size(); if (EndLineNo == LineNo) { EndColNo = SM.getExpansionColumnNumber(End); if (EndColNo) { --EndColNo; // Zero base the col #. // Add in the length of the token, so that we cover multi-char tokens if // this is a token range. if (R.isTokenRange()) EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); } else { EndColNo = CaretLine.size(); } } assert(StartColNo <= EndColNo && "Invalid range!"); // Check that a token range does not highlight only whitespace. if (R.isTokenRange()) { // Pick the first non-whitespace column. while (StartColNo < map.getSourceLine().size() && (map.getSourceLine()[StartColNo] == ' ' || map.getSourceLine()[StartColNo] == '\t')) ++StartColNo; // Pick the last non-whitespace column. if (EndColNo > map.getSourceLine().size()) EndColNo = map.getSourceLine().size(); while (EndColNo-1 && (map.getSourceLine()[EndColNo-1] == ' ' || map.getSourceLine()[EndColNo-1] == '\t')) --EndColNo; // If the start/end passed each other, then we are trying to highlight a // range that just exists in whitespace, which must be some sort of other // bug. assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); } assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); // Fill the range with ~'s. StartColNo = map.byteToColumn(StartColNo); EndColNo = map.byteToColumn(EndColNo); assert(StartColNo <= EndColNo && "Invalid range!"); if (CaretLine.size() < EndColNo) CaretLine.resize(EndColNo,' '); std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); }
void arcmt::writeARCDiagsToPlist(const std::string &outPath, ArrayRef<StoredDiagnostic> diags, SourceManager &SM, const LangOptions &LangOpts) { DiagnosticIDs DiagIDs; // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. FIDMap FM; SmallVector<FileID, 10> Fids; for (ArrayRef<StoredDiagnostic>::iterator I = diags.begin(), E = diags.end(); I != E; ++I) { const StoredDiagnostic &D = *I; AddFID(FM, Fids, SM, D.getLocation()); for (StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) { AddFID(FM, Fids, SM, RI->getBegin()); AddFID(FM, Fids, SM, RI->getEnd()); } } std::error_code EC; llvm::raw_fd_ostream o(outPath, EC, llvm::sys::fs::F_Text); if (EC) { llvm::errs() << "error: could not create file: " << outPath << '\n'; return; } EmitPlistHeader(o); // Write the root object: a <dict> containing... // - "files", an <array> mapping from FIDs to file names // - "diagnostics", an <array> containing the diagnostics o << "<dict>\n" " <key>files</key>\n" " <array>\n"; for (FileID FID : Fids) EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n'; o << " </array>\n" " <key>diagnostics</key>\n" " <array>\n"; for (ArrayRef<StoredDiagnostic>::iterator DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) { const StoredDiagnostic &D = *DI; if (D.getLevel() == DiagnosticsEngine::Ignored) continue; o << " <dict>\n"; // Output the diagnostic. o << " <key>description</key>"; EmitString(o, D.getMessage()) << '\n'; o << " <key>category</key>"; EmitString(o, DiagIDs.getCategoryNameFromID( DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n'; o << " <key>type</key>"; EmitString(o, getLevelName(D.getLevel())) << '\n'; // Output the location of the bug. o << " <key>location</key>\n"; EmitLocation(o, SM, D.getLocation(), FM, 2); // Output the ranges (if any). if (!D.getRanges().empty()) { o << " <key>ranges</key>\n"; o << " <array>\n"; for (auto &R : D.getRanges()) { CharSourceRange ExpansionRange(SM.getExpansionRange(R.getAsRange()), R.isTokenRange()); EmitRange(o, SM, Lexer::getAsCharRange(ExpansionRange, SM, LangOpts), FM, 4); } o << " </array>\n"; } // Close up the entry. o << " </dict>\n"; } o << " </array>\n"; // Finish. o << "</dict>\n</plist>"; }