1414#include < vix/cli/errors/template/ITemplateErrorRule.hpp>
1515#include < vix/cli/errors/CodeFrame.hpp>
1616
17+ #include < filesystem>
1718#include < iostream>
1819#include < memory>
20+ #include < optional>
21+ #include < regex>
1922#include < string>
23+ #include < string_view>
2024
2125#include < vix/cli/Style.hpp>
2226
@@ -62,6 +66,122 @@ namespace vix::cli::errors::template_rules
6266
6367 return false ;
6468 }
69+
70+ bool is_system_path (std::string_view path) noexcept
71+ {
72+ return path.find (" /usr/include/" ) != std::string_view::npos ||
73+ path.find (" /usr/lib/" ) != std::string_view::npos ||
74+ path.find (" /usr/local/include/" ) != std::string_view::npos ||
75+ path.find (" /usr/local/lib/" ) != std::string_view::npos ||
76+ path.find (" /lib/" ) != std::string_view::npos ||
77+ path.find (" /lib64/" ) != std::string_view::npos;
78+ }
79+
80+ bool is_user_path (std::string_view path) noexcept
81+ {
82+ if (path.empty ())
83+ return false ;
84+
85+ if (is_system_path (path))
86+ return false ;
87+
88+ return path.find (" .cpp" ) != std::string_view::npos ||
89+ path.find (" .cc" ) != std::string_view::npos ||
90+ path.find (" .cxx" ) != std::string_view::npos ||
91+ path.find (" .hpp" ) != std::string_view::npos ||
92+ path.find (" .hh" ) != std::string_view::npos ||
93+ path.find (" .h" ) != std::string_view::npos;
94+ }
95+
96+ vix::cli::errors::CompilerError make_location (
97+ const std::string &file,
98+ int line,
99+ int column,
100+ const std::string &message)
101+ {
102+ vix::cli::errors::CompilerError out;
103+ out.file = file;
104+ out.line = line;
105+ out.column = column > 0 ? column : 1 ;
106+ out.message = message;
107+ return out;
108+ }
109+
110+ std::optional<vix::cli::errors::CompilerError>
111+ try_extract_first_user_location_from_log (
112+ const std::string &log,
113+ const std::string &message)
114+ {
115+ static const std::regex re (
116+ R"( (/[^:\n]+?\.(?:c|cc|cpp|cxx|h|hpp|hh)):(\d+):(\d+))" ,
117+ std::regex::ECMAScript);
118+
119+ std::smatch match;
120+ std::string::const_iterator it = log.begin ();
121+
122+ while (std::regex_search (it, log.cend (), match, re))
123+ {
124+ const std::string file = match[1 ].str ();
125+ const int line = std::stoi (match[2 ].str ());
126+ const int column = std::stoi (match[3 ].str ());
127+
128+ if (is_user_path (file))
129+ return make_location (file, line, column, message);
130+
131+ it = match.suffix ().first ;
132+ }
133+
134+ return std::nullopt ;
135+ }
136+
137+ const std::string &compiler_log_from_context (
138+ const vix::cli::errors::ErrorContext &ctx)
139+ {
140+ return ctx.buildLog ;
141+ }
142+
143+ vix::cli::errors::CompilerError best_location (
144+ const vix::cli::errors::CompilerError &err,
145+ const vix::cli::errors::ErrorContext &ctx)
146+ {
147+ const std::string &log = compiler_log_from_context (ctx);
148+
149+ if (auto user_location =
150+ try_extract_first_user_location_from_log (log, err.message ))
151+ {
152+ return *user_location;
153+ }
154+
155+ if (is_user_path (err.file ))
156+ return err;
157+
158+ return err;
159+ }
160+
161+ void print_hint_and_at (
162+ const vix::cli::errors::CompilerError &location,
163+ const vix::cli::errors::CompilerError &original)
164+ {
165+ std::cerr << YELLOW
166+ << " hint: "
167+ << RESET
168+ << " check the type used at the call site; it does not provide the operation required by this concept"
169+ << " \n " ;
170+
171+ if (location.file != original.file )
172+ {
173+ std::cerr << GRAY
174+ << " note: original compiler location was "
175+ << original.file << " :" << original.line << " :" << original.column
176+ << RESET << " \n " ;
177+ }
178+
179+ std::cerr << GREEN
180+ << " at: "
181+ << RESET
182+ << location.file << " :" << location.line << " :" << location.column
183+ << " \n " ;
184+ }
65185 } // namespace
66186
67187 class ConceptConstraintFailureRule final : public ITemplateErrorRule
@@ -84,23 +204,20 @@ namespace vix::cli::errors::template_rules
84204 const vix::cli::errors::CompilerError &err,
85205 const vix::cli::errors::ErrorContext &ctx) const override
86206 {
207+ const auto location = best_location (err, ctx);
208+
87209 std::cerr << RED
88210 << " error: concept constraint not satisfied"
89211 << RESET << " \n " ;
90212
91- printCodeFrame (err, ctx);
213+ CodeFrameOptions options;
214+ options.contextLines = 2 ;
215+ options.maxLineWidth = 120 ;
216+ options.tabWidth = 4 ;
92217
93- std::cerr << YELLOW
94- << " hint: "
95- << RESET
96- << " check that the type provides the operations, nested types, and return types required by the concept"
97- << " \n " ;
218+ printCodeFrame (location, ctx, options);
98219
99- std::cerr << GREEN
100- << " at: "
101- << RESET
102- << err.file << " :" << err.line << " :" << err.column
103- << " \n " ;
220+ print_hint_and_at (location, err);
104221
105222 return true ;
106223 }
0 commit comments