Skip to content

Commit a4a3485

Browse files
committed
Added output of diagnostics in json format
1 parent f5ddd98 commit a4a3485

7 files changed

+13119
-0
lines changed

ArduinoDiagnosticConsumer.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,22 @@
2727
* the GNU General Public License.
2828
*/
2929

30+
#include <clang/Basic/Diagnostic.h>
31+
3032
#include "ArduinoDiagnosticConsumer.h"
3133
#include "CommandLine.h"
34+
#include "JsonImpl.hpp"
35+
36+
using namespace clang;
3237

3338
void ArduinoDiagnosticConsumer::collectUndeclaredIdentifiersIn(IdentifiersList &list) {
3439
undeclaredIdentifiersList = &list;
3540
}
3641

42+
void ArduinoDiagnosticConsumer::outputJsonDiagnosticsTo(ostream &out) {
43+
jsonDiagnosticOutput = &out;
44+
}
45+
3746
void ArduinoDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level level, const Diagnostic& info) {
3847
// DiagnosticConsumer::HandleDiagnostic(level, info);
3948

@@ -68,6 +77,21 @@ void ArduinoDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level level,
6877

6978
}
7079

80+
if (jsonDiagnosticOutput) {
81+
const SourceManager &sm = info.getSourceManager();
82+
83+
SmallString<100> message;
84+
info.FormatDiagnostic(message);
85+
86+
json data = json{
87+
{"location", encode(sm, info.getLocation())},
88+
{"message", encode(message)},
89+
{"ranges", encode(sm, info.getRanges())},
90+
{"hints", encode(sm, info.getFixItHints())},
91+
};
92+
*jsonDiagnosticOutput << data.dump() << "\n";
93+
}
94+
7195
if (debugOutput) {
7296
SmallString<100> outStr;
7397
info.FormatDiagnostic(outStr);

ArduinoDiagnosticConsumer.h

+3
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@ class ArduinoDiagnosticConsumer : public DiagnosticConsumer {
4141

4242
void collectUndeclaredIdentifiersIn(IdentifiersList &list);
4343

44+
void outputJsonDiagnosticsTo(ostream &out);
45+
4446
private:
4547
IdentifiersList *undeclaredIdentifiersList = nullptr;
48+
ostream *jsonDiagnosticOutput = nullptr;
4649

4750
void HandleDiagnostic(DiagnosticsEngine::Level level, const Diagnostic& info) override;
4851
};

CommandLine.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
using namespace std;
3636

3737
bool debugOutput;
38+
bool outputDiagnostics;
3839
bool outputOnlyNeededPrototypes;
3940

4041
static cl::OptionCategory arduinoToolCategory("Arduino options");
@@ -46,6 +47,7 @@ static cl::extrahelp arduinoHelp("\n"
4647
static cl::extrahelp commonHelp(CommonOptionsParser::HelpMessage);
4748
static cl::opt<bool> debugOutputOpt("debug");
4849
static cl::opt<bool> outputOnlyNeededPrototypesOpt("output-only-needed-prototypes");
50+
static cl::opt<bool> outputDiagnosticsOpt("diagnostics");
4951

5052
static void printVersion() {
5153
cout << "Arduino (https://www.arduino.cc/):\n";
@@ -61,12 +63,17 @@ CommonOptionsParser doCommandLineParsing(int argc, const char **argv) {
6163
outputOnlyNeededPrototypesOpt.setInitialValue(false);
6264
outputOnlyNeededPrototypesOpt.setDescription("Output a prototype only if a forward declaration is needed (experimental)");
6365

66+
outputDiagnosticsOpt.setCategory(arduinoToolCategory);
67+
outputDiagnosticsOpt.setInitialValue(false);
68+
outputDiagnosticsOpt.setDescription("Output diagnostics (warnings/errors) in json format");
69+
6470
cl::AddExtraVersionPrinter(printVersion);
6571

6672
CommonOptionsParser optParser(argc, argv, arduinoToolCategory);
6773

6874
debugOutput = debugOutputOpt.getValue();
6975
outputOnlyNeededPrototypes = outputOnlyNeededPrototypesOpt.getValue();
76+
outputDiagnostics = outputDiagnosticsOpt.getValue();
7077

7178
return optParser;
7279
}

CommandLine.h

+1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ using namespace llvm;
3838

3939
extern bool debugOutput;
4040
extern bool outputOnlyNeededPrototypes;
41+
extern bool outputDiagnostics;
4142

4243
CommonOptionsParser doCommandLineParsing(int argc, const char **argv);

JsonImpl.hpp

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* This file is part of arduino-preprocessor.
3+
*
4+
* Copyright 2017 BCMI LABS SA
5+
*
6+
* arduino-preprocessor is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*
20+
* As a special exception, you may use this file as part of a free software
21+
* library without restriction. Specifically, if other files instantiate
22+
* templates or use macros or inline functions from this file, or you compile
23+
* this file and link it with other files to produce an executable, this
24+
* file does not by itself cause the resulting executable to be covered by
25+
* the GNU General Public License. This exception does not however
26+
* invalidate any other reasons why the executable file might be covered by
27+
* the GNU General Public License.
28+
*/
29+
30+
#pragma once
31+
32+
#include <clang/AST/ASTConsumer.h>
33+
#include <sstream>
34+
35+
using namespace clang;
36+
using namespace std;
37+
38+
#define JSON_NOEXCEPTION
39+
#include "json.hpp"
40+
#include "clang/include/clang/Basic/SourceManager.h"
41+
using json = nlohmann::json;
42+
43+
template<unsigned InternalLen>
44+
inline string encode(const SmallString<InternalLen> &s) {
45+
return s.str().str();
46+
}
47+
48+
inline json encode(const SourceManager &sm, const SourceLocation &loc) {
49+
PresumedLoc presumed = sm.getPresumedLoc(loc);
50+
stringstream pos;
51+
pos << presumed.getLine() << ":" << presumed.getColumn();
52+
return json{
53+
{"file", presumed.getFilename()},
54+
{"pos", pos.str()}};
55+
}
56+
57+
inline json encode(const SourceManager &sm, const CharSourceRange &range) {
58+
if (range.isInvalid()) {
59+
return json{};
60+
}
61+
return json{
62+
{"begin", encode(sm, range.getBegin())},
63+
{"end", encode(sm, range.getEnd())}};
64+
}
65+
66+
inline json encode(const SourceManager &sm, const FixItHint &hint) {
67+
return json{
68+
{"before_previous", hint.BeforePreviousInsertions},
69+
{"text", hint.CodeToInsert},
70+
{"insert_from", encode(sm, hint.InsertFromRange)},
71+
{"remove", encode(sm, hint.RemoveRange)}};
72+
}
73+
74+
template<typename T>
75+
inline json encode(const SourceManager &sm, const ArrayRef<T> &array) {
76+
json res = json::array();
77+
for (T elem : array) {
78+
res.push_back(encode(sm, elem));
79+
}
80+
return res;
81+
}

0 commit comments

Comments
 (0)