Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/csgrep.cc
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ int main(int argc, char *argv[])
("file-glob", "expand glob patterns in the names of input files")
("ignore-case,i", "ignore case when matching regular expressions")
("ignore-parser-warnings", "if enabled, parser warnings about the input files do not affect exit code")
("record-input-locations", "if enabled, events in json will contain input_line and input_file fields referencing the original location of input file/stream")
("invert-match,v", "select defects that do not match the selected criteria")
("invert-regex,n", "invert regular expressions in all predicates")
("filter-file,f", po::value<TStringList>(), "read custom filtering rules from a file in JSON format");
Expand All @@ -639,7 +640,7 @@ int main(int argc, char *argv[])
p.add("input-file", -1);

po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
po::notify(vm);

po::options_description opts;
opts.add(desc).add(hidden);
Expand Down Expand Up @@ -735,6 +736,9 @@ int main(int argc, char *argv[])
if (vm.count("ignore-parser-warnings"))
eng->setIgnoreParserWarnings(true);

if (vm.count("record-input-locations"))
eng->setRecordInputLocations(true);

bool hasError = false;

// if no input file is given, read from stdin
Expand Down
2 changes: 2 additions & 0 deletions src/lib/defect.hh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ struct DefEvent {
std::string fileName;
int line = 0;
int column = 0;
int inputLine = 0;
Comment thread
Jany26 marked this conversation as resolved.
std::string inputFile;
std::string event;
std::string msg;

Expand Down
3 changes: 2 additions & 1 deletion src/lib/instream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@

#include "instream.hh"

InStream::InStream(const std::string &fileName, const bool silent):
InStream::InStream(const std::string &fileName, const bool silent, const bool recordInputLocations):
fileName_(fileName),
silent_(silent),
recordInputLocations_(recordInputLocations),
str_((fileName_ == "-")
? std::cin
: fileStr_)
Expand Down
13 changes: 8 additions & 5 deletions src/lib/instream.hh
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,23 @@ struct InFileException {

class InStream {
public:
InStream(const std::string &fileName, bool silent = false);
InStream(const std::string &fileName, bool silent = false,
bool recordInputLocations = false);
InStream(std::istringstream &str, bool silent = false);
~InStream() = default;

const std::string& fileName() const { return fileName_; }
std::istream& str() const { return str_; }
bool silent() const { return silent_; }
bool anyError() const { return anyError_; }
const std::string& fileName() const { return fileName_; }
std::istream& str() const { return str_; }
bool silent() const { return silent_; }
bool recordInputLocations() const { return recordInputLocations_; }
bool anyError() const { return anyError_; }

void handleError(const std::string &msg = "", unsigned long line = 0UL);

private:
const std::string fileName_;
const bool silent_;
const bool recordInputLocations_ = false;
bool anyError_ = false;
std::ifstream fileStr_;
std::istream &str_;
Expand Down
19 changes: 16 additions & 3 deletions src/lib/parser-cov.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ std::ostream& operator<<(std::ostream &str, EToken code)

class ErrFileLexer {
public:
ErrFileLexer(std::istream &input):
lineReader_(input),
ErrFileLexer(InStream &input):
lineReader_(input.str()),
fileName_(input.fileName()),
recordInputLocations_(input.recordInputLocations()),
hasError_(false)
{
}
Expand All @@ -140,6 +142,8 @@ class ErrFileLexer {

private:
LineReader lineReader_;
std::string fileName_;
bool recordInputLocations_;
bool hasError_;
Defect def_;
DefEvent evt_;
Expand Down Expand Up @@ -181,6 +185,10 @@ EToken ErrFileLexer::readNext()
evt_ = DefEvent();
evt_.event = sm[/* # */ 1];
evt_.msg = sm[/* msg */ 2];
if (recordInputLocations_) {
evt_.inputLine = lineReader_.lineNo();
evt_.inputFile = fileName_;
}
return T_COMMENT;
}

Expand All @@ -202,6 +210,11 @@ EToken ErrFileLexer::readNext()
evt_.event = sm[/* event */ 4];
evt_.msg = sm[/* msg */ 5];

if (recordInputLocations_) {
evt_.inputLine = lineReader_.lineNo();
evt_.inputFile = fileName_;
}

return T_EVENT;
}

Expand Down Expand Up @@ -523,7 +536,7 @@ struct CovParser::Private {
ImpliedAttrDigger digger;

Private(InStream &input_):
lexer(input_.str()),
lexer(input_),
fileName(input_.fileName()),
silent(input_.silent()),
hasError(false),
Expand Down
20 changes: 15 additions & 5 deletions src/lib/parser-gcc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ class AbstractTokenFilter: public ITokenizer {

class Tokenizer: public ITokenizer {
public:
Tokenizer(std::istream &input):
input_(input),
lineNo_(0)
Tokenizer(InStream &input):
input_(input.str()),
lineNo_(0),
fileName_(input.fileName()),
recordInputLocations_(input.recordInputLocations())
{
}

Expand All @@ -83,6 +85,8 @@ class Tokenizer: public ITokenizer {
private:
std::istream &input_;
int lineNo_;
std::string fileName_;
bool recordInputLocations_;

const RE reSideBar_ =
RE("^ *((([0-9]+)? \\| )|(\\+\\+\\+ \\|\\+)).*$");
Expand Down Expand Up @@ -131,6 +135,11 @@ EToken Tokenizer::readNext(DefEvent *pEvt)
*pEvt = DefEvent();
pEvt->msg = line;

if (recordInputLocations_) {
pEvt->inputLine = lineNo_;
pEvt->inputFile = fileName_;
}

// check for line markers produced by gcc-9.2.1 (a.k.a. sidebar)
if (boost::regex_match(pEvt->msg, reSideBar_))
// xxx.c:2:1: note: include '<stdlib.h>' or provide a declaration...
Expand Down Expand Up @@ -387,7 +396,7 @@ EToken MultilineConcatenator::readNext(DefEvent *pEvt)
class BasicGccParser {
public:
BasicGccParser(InStream &input):
rawTokenizer_(input.str()),
rawTokenizer_(input),
noiseFilter_(&rawTokenizer_),
markerConverter_(&noiseFilter_),
tokenizer_(&markerConverter_),
Expand Down Expand Up @@ -535,6 +544,7 @@ bool BasicGccParser::getNext(Defect *pDef)
DefEvent evt;

const EToken tok = tokenizer_.readNext(&evt);

switch (tok) {
case T_NULL:
if (!hasKeyEvent_ && !defCurrent_.events.empty())
Expand Down Expand Up @@ -828,7 +838,7 @@ bool GccParser::getNext(Defect *pDef)
while (d->core.getNext(&d->lastDef) && d->tryMerge(pDef))
;

// initialize verbosityLevel
// initialize verbosityLevel
// FIXME: similar code to KeyEventDigger::initVerbosity()
TEvtList &evtList = pDef->events;
const unsigned evtCount = evtList.size();
Expand Down
5 changes: 4 additions & 1 deletion src/lib/parser-json-simple.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ SimpleTreeDecoder::Private::Private(InStream &input):
"event",
"file_name",
"h_size",
"input_file",
"input_line",
"line",
"message",
"v_size",
Expand Down Expand Up @@ -148,6 +150,8 @@ bool SimpleTreeDecoder::readNode(Defect *def)
evt.column = valueOf<int >(evtNode, "column");
evt.hSize = valueOf<TNumDiff >(evtNode, "h_size");
evt.vSize = valueOf<TNumDiff >(evtNode, "v_size");
evt.inputFile = valueOf<std::string >(evtNode, "input_file");
evt.inputLine = valueOf<int >(evtNode, "input_line");
evt.event = valueOf<std::string >(evtNode, "event");
evt.msg = valueOf<std::string >(evtNode, "message");
evt.verbosityLevel = valueOf<int>(evtNode, "verbosity_level", -1);
Expand Down Expand Up @@ -189,4 +193,3 @@ bool SimpleTreeDecoder::readNode(Defect *def)

return true;
}

8 changes: 7 additions & 1 deletion src/lib/writer-json-simple.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static array simpleEncodeEvents(const TEvtList &events)
for (const DefEvent &evt : events) {
object evtNode;

// describe the location
// describe the location from the source code
evtNode["file_name"] = evt.fileName;
evtNode["line"] = evt.line;
if (0 < evt.column)
Expand All @@ -50,6 +50,12 @@ static array simpleEncodeEvents(const TEvtList &events)
if (0 < evt.vSize)
evtNode["v_size"] = evt.vSize;

// describe the location from the compilation error log/input
if (!evt.inputFile.empty())
evtNode["input_file"] = evt.inputFile;
if (0 < evt.inputLine)
evtNode["input_line"] = evt.inputLine;
Comment thread
Jany26 marked this conversation as resolved.

// describe the event
evtNode["event"] = evt.event;
evtNode["message"] = sanitizeUTF8(evt.msg);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ bool AbstractWriter::handleFile(InStream &input)
bool AbstractWriter::handleFile(const std::string &fileName, bool silent)
{
try {
InStream str(fileName, silent);
InStream str(fileName, silent, recordInputLocations_);
return this->handleFile(str);
}
catch (const InFileException &e) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/writer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,15 @@ class AbstractWriter {
ignoreParserWarnings_ = val;
}

void setRecordInputLocations(const bool val) {
recordInputLocations_ = val;
}

private:
EFileFormat inputFormat_ = FF_INVALID;
const TScanProps emptyProps_{};
bool ignoreParserWarnings_ = false;
bool recordInputLocations_ = false;
};

using TWriterPtr = std::unique_ptr<AbstractWriter>;
Expand Down
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ set(diffcmd "diff -up")
set(jsfilter "sed -e 's|\"version\": \"[^\"]*\"|\"version\": \"\"|g'")
set(jsfilter "${jsfilter} -e 's|${CMAKE_SOURCE_DIR}/tests/csfilter-kfp/|\$PROJECT_ROOT/tests/csfilter-kfp/|'")

# strip the absolute paths for "input_file" strings in the --record-input-locations tests
# (namely csgrep/0134 test) for portability
set(jsfilter "${jsfilter} -e 's|${CMAKE_SOURCE_DIR}/tests/csgrep/0134|0134|g'")

macro(add_test_wrap test_name cmd)
add_test("${test_name}" bash -c "${cmd}")
set_tests_properties(${test_name} PROPERTIES ENVIRONMENT
Expand Down
1 change: 1 addition & 0 deletions tests/csgrep/0134-json-record-locations-args.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--mode=json --record-input-locations
7 changes: 7 additions & 0 deletions tests/csgrep/0134-json-record-locations-stdin.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Error: SHELLCHECK_WARNING:
/etc/rc.d/rc.sysinit:492:13: warning: Quote this to prevent word splitting. [SC2046]
# 490| if [ -n "$SELINUX_STATE" -a "$READONLY" != "yes" ]; then
# 491| if [ -f /.autorelabel ] || strstr "$cmdline" autorelabel ; then
# 492|-> restorecon $(awk '!/^#/ && $4 !~ /noauto/ && $2 ~ /^\// { print $2 }' /etc/fstab) >/dev/null 2>&1
# 493| fi
# 494| fi
68 changes: 68 additions & 0 deletions tests/csgrep/0134-json-record-locations-stdout.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"defects": [
{
"checker": "SHELLCHECK_WARNING",
"language": "shell",
"tool": "shellcheck",
"hash_v1": "b6311c1fdc52c47d4279cd6650af36e6f8299960",
"key_event_idx": 0,
"events": [
{
"file_name": "/etc/rc.d/rc.sysinit",
"line": 492,
"column": 13,
"input_file": "0134-json-record-locations-stdin.txt",
"input_line": 2,
"event": "warning",
"message": "Quote this to prevent word splitting. [SC2046]",
"verbosity_level": 0
},
{
"file_name": "",
"line": 0,
"input_file": "0134-json-record-locations-stdin.txt",
"input_line": 3,
"event": "#",
"message": " 490| if [ -n \"$SELINUX_STATE\" -a \"$READONLY\" != \"yes\" ]; then",
"verbosity_level": 1
},
{
"file_name": "",
"line": 0,
"input_file": "0134-json-record-locations-stdin.txt",
"input_line": 4,
"event": "#",
"message": " 491| if [ -f /.autorelabel ] || strstr \"$cmdline\" autorelabel ; then",
"verbosity_level": 1
},
{
"file_name": "",
"line": 0,
"input_file": "0134-json-record-locations-stdin.txt",
"input_line": 5,
"event": "#",
"message": " 492|-> \trestorecon $(awk '!/^#/ && $4 !~ /noauto/ && $2 ~ /^\\// { print $2 }' /etc/fstab) >/dev/null 2>&1",
"verbosity_level": 1
},
{
"file_name": "",
"line": 0,
"input_file": "0134-json-record-locations-stdin.txt",
"input_line": 6,
"event": "#",
"message": " 493| fi",
"verbosity_level": 1
},
{
"file_name": "",
"line": 0,
"input_file": "0134-json-record-locations-stdin.txt",
"input_line": 7,
"event": "#",
"message": " 494| fi",
"verbosity_level": 1
}
]
}
]
}
Empty file.
Loading