10b57cec5SDimitry Andric 20b57cec5SDimitry Andric //===--- CommandLineSourceLoc.h - Parsing for source locations-*- C++ -*---===// 30b57cec5SDimitry Andric // 40b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 50b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 60b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 70b57cec5SDimitry Andric // 80b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 90b57cec5SDimitry Andric // 100b57cec5SDimitry Andric // Command line parsing for source locations. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H 150b57cec5SDimitry Andric #define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 180b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 20*bdd1243dSDimitry Andric #include <optional> 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric namespace clang { 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric /// A source location that has been parsed on the command line. 250b57cec5SDimitry Andric struct ParsedSourceLocation { 260b57cec5SDimitry Andric std::string FileName; 270b57cec5SDimitry Andric unsigned Line; 280b57cec5SDimitry Andric unsigned Column; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric public: 310b57cec5SDimitry Andric /// Construct a parsed source location from a string; the Filename is empty on 320b57cec5SDimitry Andric /// error. FromStringParsedSourceLocation330b57cec5SDimitry Andric static ParsedSourceLocation FromString(StringRef Str) { 340b57cec5SDimitry Andric ParsedSourceLocation PSL; 350b57cec5SDimitry Andric std::pair<StringRef, StringRef> ColSplit = Str.rsplit(':'); 360b57cec5SDimitry Andric std::pair<StringRef, StringRef> LineSplit = 370b57cec5SDimitry Andric ColSplit.first.rsplit(':'); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric // If both tail splits were valid integers, return success. 400b57cec5SDimitry Andric if (!ColSplit.second.getAsInteger(10, PSL.Column) && 410b57cec5SDimitry Andric !LineSplit.second.getAsInteger(10, PSL.Line)) { 425ffd83dbSDimitry Andric PSL.FileName = std::string(LineSplit.first); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // On the command-line, stdin may be specified via "-". Inside the 450b57cec5SDimitry Andric // compiler, stdin is called "<stdin>". 460b57cec5SDimitry Andric if (PSL.FileName == "-") 470b57cec5SDimitry Andric PSL.FileName = "<stdin>"; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric return PSL; 510b57cec5SDimitry Andric } 52fe6060f1SDimitry Andric 53fe6060f1SDimitry Andric /// Serialize ParsedSourceLocation back to a string. ToStringParsedSourceLocation54fe6060f1SDimitry Andric std::string ToString() const { 55fe6060f1SDimitry Andric return (llvm::Twine(FileName == "<stdin>" ? "-" : FileName) + ":" + 56fe6060f1SDimitry Andric Twine(Line) + ":" + Twine(Column)) 57fe6060f1SDimitry Andric .str(); 58fe6060f1SDimitry Andric } 590b57cec5SDimitry Andric }; 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric /// A source range that has been parsed on the command line. 620b57cec5SDimitry Andric struct ParsedSourceRange { 630b57cec5SDimitry Andric std::string FileName; 640b57cec5SDimitry Andric /// The starting location of the range. The first element is the line and 650b57cec5SDimitry Andric /// the second element is the column. 660b57cec5SDimitry Andric std::pair<unsigned, unsigned> Begin; 670b57cec5SDimitry Andric /// The ending location of the range. The first element is the line and the 680b57cec5SDimitry Andric /// second element is the column. 690b57cec5SDimitry Andric std::pair<unsigned, unsigned> End; 700b57cec5SDimitry Andric 71*bdd1243dSDimitry Andric /// Returns a parsed source range from a string or std::nullopt if the string 72*bdd1243dSDimitry Andric /// is invalid. 730b57cec5SDimitry Andric /// 740b57cec5SDimitry Andric /// These source string has the following format: 750b57cec5SDimitry Andric /// 760b57cec5SDimitry Andric /// file:start_line:start_column[-end_line:end_column] 770b57cec5SDimitry Andric /// 780b57cec5SDimitry Andric /// If the end line and column are omitted, the starting line and columns 790b57cec5SDimitry Andric /// are used as the end values. fromStringParsedSourceRange80*bdd1243dSDimitry Andric static std::optional<ParsedSourceRange> fromString(StringRef Str) { 810b57cec5SDimitry Andric std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-'); 820b57cec5SDimitry Andric unsigned EndLine, EndColumn; 830b57cec5SDimitry Andric bool HasEndLoc = false; 840b57cec5SDimitry Andric if (!RangeSplit.second.empty()) { 850b57cec5SDimitry Andric std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':'); 860b57cec5SDimitry Andric if (Split.first.getAsInteger(10, EndLine) || 870b57cec5SDimitry Andric Split.second.getAsInteger(10, EndColumn)) { 880b57cec5SDimitry Andric // The string does not end in end_line:end_column, so the '-' 890b57cec5SDimitry Andric // probably belongs to the filename which menas the whole 900b57cec5SDimitry Andric // string should be parsed. 910b57cec5SDimitry Andric RangeSplit.first = Str; 920b57cec5SDimitry Andric } else 930b57cec5SDimitry Andric HasEndLoc = true; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric auto Begin = ParsedSourceLocation::FromString(RangeSplit.first); 960b57cec5SDimitry Andric if (Begin.FileName.empty()) 97*bdd1243dSDimitry Andric return std::nullopt; 980b57cec5SDimitry Andric if (!HasEndLoc) { 990b57cec5SDimitry Andric EndLine = Begin.Line; 1000b57cec5SDimitry Andric EndColumn = Begin.Column; 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric return ParsedSourceRange{std::move(Begin.FileName), 1030b57cec5SDimitry Andric {Begin.Line, Begin.Column}, 1040b57cec5SDimitry Andric {EndLine, EndColumn}}; 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric }; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric namespace llvm { 1100b57cec5SDimitry Andric namespace cl { 1110b57cec5SDimitry Andric /// Command-line option parser that parses source locations. 1120b57cec5SDimitry Andric /// 1130b57cec5SDimitry Andric /// Source locations are of the form filename:line:column. 1140b57cec5SDimitry Andric template<> 1150b57cec5SDimitry Andric class parser<clang::ParsedSourceLocation> final 1160b57cec5SDimitry Andric : public basic_parser<clang::ParsedSourceLocation> { 1170b57cec5SDimitry Andric public: 1180b57cec5SDimitry Andric inline bool parse(Option &O, StringRef ArgName, StringRef ArgValue, 1190b57cec5SDimitry Andric clang::ParsedSourceLocation &Val); 1200b57cec5SDimitry Andric }; 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric bool 1230b57cec5SDimitry Andric parser<clang::ParsedSourceLocation>:: parse(Option & O,StringRef ArgName,StringRef ArgValue,clang::ParsedSourceLocation & Val)1240b57cec5SDimitry Andric parse(Option &O, StringRef ArgName, StringRef ArgValue, 1250b57cec5SDimitry Andric clang::ParsedSourceLocation &Val) { 1260b57cec5SDimitry Andric using namespace clang; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric Val = ParsedSourceLocation::FromString(ArgValue); 1290b57cec5SDimitry Andric if (Val.FileName.empty()) { 1300b57cec5SDimitry Andric errs() << "error: " 1310b57cec5SDimitry Andric << "source location must be of the form filename:line:column\n"; 1320b57cec5SDimitry Andric return true; 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric return false; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric #endif 141