Skip to content

Commit b979ab8

Browse files
committed
[Heavy] Improve Clang diagnostics integration
1 parent 9a077e4 commit b979ab8

File tree

5 files changed

+79
-17
lines changed

5 files changed

+79
-17
lines changed

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,9 @@ def warn_try_not_valid_on_target : Warning<
463463

464464
// HeavyScheme
465465
def err_heavy_scheme : Error<
466-
"(HeavyScheme) %0">;
466+
"(heavy_scheme) %0">;
467467
def warn_heavy_scheme : Warning<
468-
"(HeavyScheme) %0">;
468+
"(heavy_scheme) %0">;
469+
def note_heavy_scheme : Note<
470+
"(heavy_scheme) %0">;
469471
}

clang/lib/Parse/ParseDeclHeavy.cpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ using namespace clang;
3232

3333
bool HEAVY_CLANG_IS_LOADED = false;
3434
heavy::ContextLocal HEAVY_CLANG_VAR(diag_error);
35+
heavy::ContextLocal HEAVY_CLANG_VAR(diag_warning);
36+
heavy::ContextLocal HEAVY_CLANG_VAR(diag_note);
3537
heavy::ContextLocal HEAVY_CLANG_VAR(hello_world);
3638
heavy::ContextLocal HEAVY_CLANG_VAR(write_lexer);
3739
heavy::ContextLocal HEAVY_CLANG_VAR(lexer_writer);
@@ -47,6 +49,12 @@ clang::SourceLocation getSourceLocation(heavy::FullSourceLocation Loc) {
4749
.getLocWithOffset(Loc.getOffset());
4850
}
4951

52+
clang::SourceLocation getSourceLocation(heavy::HeavyScheme& HS,
53+
heavy::SourceLocation Loc) {
54+
heavy::FullSourceLocation FullLoc = HS.getFullSourceLocation(Loc);
55+
return getSourceLocation(FullLoc);
56+
}
57+
5058
// It is complicated to keep the TokenBuffer alive
5159
// for the Preprocessor, so we use an array to give
5260
// ownership via the EnterTokenStream overload.
@@ -135,20 +143,31 @@ bool Parser::ParseHeavyScheme() {
135143
// Load the static builtin module.
136144
Parser& P = *this;
137145
heavy::HeavyScheme& HS = *HeavyScheme;
138-
auto diag_error = [&](heavy::Context& C, heavy::ValueRefs Args) {
139-
if (Args.size() != 1) {
140-
C.RaiseError("invalid arity to function", C.getCallee());
141-
return;
142-
}
143-
if (!isa<heavy::String, heavy::Symbol>(Args[0])) {
144-
C.RaiseError("expecting string or identifier", C.getCallee());
145-
return;
146-
}
147-
llvm::StringRef Err = Args[0].getStringRef();
146+
auto diag_gen = [&](auto DiagKind) {
147+
return [&, DiagKind](heavy::Context& C, heavy::ValueRefs Args) {
148+
if (Args.size() < 1 || Args.size() > 2) {
149+
C.RaiseError("invalid arity to function", C.getCallee());
150+
return;
151+
}
148152

149-
P.Diag(clang::SourceLocation{}, diag::err_heavy_scheme) << Err;
150-
C.Cont();
153+
if (!isa<heavy::String, heavy::Symbol>(Args[0])) {
154+
C.RaiseError("expecting string or identifier", C.getCallee());
155+
return;
156+
}
157+
158+
llvm::StringRef Err = Args[0].getStringRef();
159+
heavy::SourceLocation Loc;
160+
if (Args.size() > 1)
161+
Loc = Args[1].getSourceLocation();
162+
163+
clang::SourceLocation CLoc = getSourceLocation(HS, Loc);
164+
P.Diag(CLoc, DiagKind) << Err;
165+
C.Cont();
166+
};
151167
};
168+
auto diag_error = diag_gen(diag::err_heavy_scheme);
169+
auto diag_warning = diag_gen(diag::warn_heavy_scheme);
170+
auto diag_note = diag_gen(diag::note_heavy_scheme);
152171

153172
auto hello_world = [](heavy::Context& C, heavy::ValueRefs Args) {
154173
llvm::errs() << "hello world (from clang)\n";
@@ -300,6 +319,10 @@ bool Parser::ParseHeavyScheme() {
300319
heavy::base::InitParseSourceFile(Context, ParseSourceFileFn);
301320
HEAVY_CLANG_VAR(diag_error).init(Context,
302321
Context.CreateLambda(diag_error));
322+
HEAVY_CLANG_VAR(diag_warning).init(Context,
323+
Context.CreateLambda(diag_warning));
324+
HEAVY_CLANG_VAR(diag_note).init(Context,
325+
Context.CreateLambda(diag_note));
303326
HEAVY_CLANG_VAR(hello_world).init(Context,
304327
Context.CreateLambda(hello_world));
305328
HEAVY_CLANG_VAR(expr_eval).init(Context,

heavy/include/heavy/Clang.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,19 @@
2525
#define HEAVY_CLANG_INIT HEAVY_CLANG_LIB##_init
2626
#define HEAVY_CLANG_VAR(NAME) HEAVY_CLANG_VAR__##NAME
2727
#define HEAVY_CLANG_VAR__diag_error HEAVY_CLANG_LIB_(VS4diagmi5Serror)
28+
#define HEAVY_CLANG_VAR__diag_warning HEAVY_CLANG_LIB_(VS4diagmi7Swarning)
29+
#define HEAVY_CLANG_VAR__diag_note HEAVY_CLANG_LIB_(VS4diagmi4Snote)
2830
#define HEAVY_CLANG_VAR__hello_world HEAVY_CLANG_LIB_(V5Shellomi5Sworld)
2931
#define HEAVY_CLANG_VAR__write_lexer HEAVY_CLANG_LIB_(V5Swritemi5Slexer)
3032
#define HEAVY_CLANG_VAR__lexer_writer HEAVY_CLANG_LIB_(V5Slexermi6Swriter)
3133
#define HEAVY_CLANG_VAR__expr_eval HEAVY_CLANG_LIB_(V4Sexprmi4Seval)
3234

3335
// diag-error
36+
// diag-warning
37+
// diag-note
3438
extern heavy::ContextLocal HEAVY_CLANG_VAR(diag_error);
39+
extern heavy::ContextLocal HEAVY_CLANG_VAR(diag_warning);
40+
extern heavy::ContextLocal HEAVY_CLANG_VAR(diag_note);
3541

3642
// hello-world
3743
extern heavy::ContextLocal HEAVY_CLANG_VAR(hello_world);
@@ -50,6 +56,10 @@ extern "C" {
5056
inline void HEAVY_CLANG_INIT(heavy::Context& Context) {
5157
assert(HEAVY_CLANG_VAR(diag_error).get(Context) &&
5258
"external module must be preloaded");
59+
assert(HEAVY_CLANG_VAR(diag_warning).get(Context) &&
60+
"external module must be preloaded");
61+
assert(HEAVY_CLANG_VAR(diag_note).get(Context) &&
62+
"external module must be preloaded");
5363
assert(HEAVY_CLANG_VAR(hello_world).get(Context) &&
5464
"external module must be preloaded");
5565
assert(HEAVY_CLANG_VAR(write_lexer).get(Context) &&
@@ -66,6 +76,8 @@ inline void HEAVY_CLANG_LOAD_MODULE(heavy::Context& Context) {
6676
HEAVY_CLANG_INIT(Context);
6777
heavy::initModuleNames(Context, HEAVY_CLANG_LIB_STR, {
6878
{"diag-error", HEAVY_CLANG_VAR(diag_error).init(Context)},
79+
{"diag-warning", HEAVY_CLANG_VAR(diag_warning).init(Context)},
80+
{"diag-note", HEAVY_CLANG_VAR(diag_note).init(Context)},
6981
{"hello-world", HEAVY_CLANG_VAR(hello_world).init(Context)},
7082
{"write-lexer", HEAVY_CLANG_VAR(write_lexer).init(Context)},
7183
{"lexer-writer",HEAVY_CLANG_VAR(lexer_writer).init(Context)},

heavy/lib/Builtins.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,14 @@ void parse_source_file(Context& C, ValueRefs Args) {
331331
}
332332

333333
void source_loc(Context& C, ValueRefs Args) {
334-
if (Args.size() != 1)
335-
return C.RaiseError("expecting single argument");
336-
C.Cont(C.CreateSourceValue(Args[0].getSourceLocation()));
334+
heavy::SourceLocation Loc;
335+
// Take the first valid source location.
336+
for (heavy::Value Arg : Args) {
337+
Loc = Arg.getSourceLocation();
338+
if (Loc.isValid())
339+
break;
340+
}
341+
C.Cont(C.CreateSourceValue(Loc));
337342
}
338343

339344
} // end of namespace heavy::base

heavy/test/Clang/source-loc.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: clang++ -I %S/Inputs -fsyntax-only -Xclang -fheavy -Xclang -verify %s
2+
3+
#include <type_traits>
4+
5+
// Note that a note requires an error or a warning in order to be displayed.
6+
// expected-warning@12{{this is a foo}}
7+
// expected-error@12{{this is still a foo}}
8+
// expected-note@14{{this is a bar in a list}}
9+
namespace foo {
10+
heavy_scheme {
11+
(import (heavy base) (heavy clang))
12+
(define foo 'foo)
13+
(define bar "bar")
14+
(define baz '(foo bar))
15+
16+
(diag-warning "this is a foo" (source-loc foo))
17+
(diag-error "this is still a foo" (source-loc bar foo))
18+
(diag-note "this is a bar in a list" (source-loc (cdr baz) bar foo))
19+
}
20+
}

0 commit comments

Comments
 (0)