Skip to content

Commit 4d5922a

Browse files
committed
feat(cli): add modern C++ template diagnostics
2 parents 96d32b0 + cd85852 commit 4d5922a

22 files changed

Lines changed: 2615 additions & 1 deletion

include/vix/cli/errors/template/ITemplateErrorRule.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ namespace vix::cli::errors::template_rules
5454
std::unique_ptr<ITemplateErrorRule> makeObjectSlicingRule();
5555
std::unique_ptr<ITemplateErrorRule> makeBadOverrideRule();
5656
std::unique_ptr<ITemplateErrorRule> makeInvalidDowncastRule();
57+
std::unique_ptr<ITemplateErrorRule> makeAmbiguousOverloadRule();
58+
std::unique_ptr<ITemplateErrorRule> makeDeletedFunctionRule();
59+
std::unique_ptr<ITemplateErrorRule> makeInaccessibleMemberRule();
60+
std::unique_ptr<ITemplateErrorRule> makeIncompleteTypeRule();
61+
std::unique_ptr<ITemplateErrorRule> makeNoViableConversionRule();
62+
std::unique_ptr<ITemplateErrorRule> makeConstQualifierRule();
63+
std::unique_ptr<ITemplateErrorRule> makeInvalidReferenceBindingRule();
64+
std::unique_ptr<ITemplateErrorRule> makeStaticAssertFailureRule();
65+
std::unique_ptr<ITemplateErrorRule> makeConstexprEvaluationFailureRule();
66+
std::unique_ptr<ITemplateErrorRule> makeCtadFailureRule();
67+
std::unique_ptr<ITemplateErrorRule> makeInvalidInitializerListRule();
68+
std::unique_ptr<ITemplateErrorRule> makeNarrowingConversionRule();
69+
std::unique_ptr<ITemplateErrorRule> makeMissingBeginEndRule();
70+
std::unique_ptr<ITemplateErrorRule> makeOperatorNotFoundRule();
71+
std::unique_ptr<ITemplateErrorRule> makeInvalidTemplateTemplateArgumentRule();
72+
std::unique_ptr<ITemplateErrorRule> makeAllocatorValueTypeMismatchRule();
73+
std::unique_ptr<ITemplateErrorRule> makeTupleVariantAccessRule();
74+
std::unique_ptr<ITemplateErrorRule> makeInvalidUseOfVoidRule();
75+
std::unique_ptr<ITemplateErrorRule> makePrivateConstructorRule();
76+
std::unique_ptr<ITemplateErrorRule> makeMoveOnlyCopyRule();
5777
} // namespace vix::cli::errors::template_rules
5878

5979
#endif

src/errors/ErrorPipeline.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,55 @@ namespace vix::cli::errors
2222
ErrorPipeline::ErrorPipeline()
2323
{
2424
// Template-specific compile errors
25+
26+
// Template parameter / deduction family (most specific first)
2527
templateRules_.push_back(vix::cli::errors::template_rules::makeDependentTypenameRule());
2628
templateRules_.push_back(vix::cli::errors::template_rules::makeNoTypeNamedRule());
2729
templateRules_.push_back(vix::cli::errors::template_rules::makeTemplateArgumentMismatchRule());
30+
templateRules_.push_back(vix::cli::errors::template_rules::makeInvalidTemplateTemplateArgumentRule());
31+
templateRules_.push_back(vix::cli::errors::template_rules::makeCtadFailureRule());
2832
templateRules_.push_back(vix::cli::errors::template_rules::makeRequiresExpressionFailureRule());
2933
templateRules_.push_back(vix::cli::errors::template_rules::makeConceptConstraintFailureRule());
3034
templateRules_.push_back(vix::cli::errors::template_rules::makeNoMatchingOverloadWithConstraintsRule());
35+
templateRules_.push_back(vix::cli::errors::template_rules::makeSubstitutionFailureRule());
36+
37+
// Compile-time evaluation family
38+
templateRules_.push_back(vix::cli::errors::template_rules::makeStaticAssertFailureRule());
39+
templateRules_.push_back(vix::cli::errors::template_rules::makeConstexprEvaluationFailureRule());
40+
41+
// Ownership / access / conversion family (specific before generic)
42+
templateRules_.push_back(vix::cli::errors::template_rules::makeMoveOnlyCopyRule());
43+
templateRules_.push_back(vix::cli::errors::template_rules::makeDeletedFunctionRule());
44+
templateRules_.push_back(vix::cli::errors::template_rules::makePrivateConstructorRule());
45+
templateRules_.push_back(vix::cli::errors::template_rules::makeInaccessibleMemberRule());
46+
templateRules_.push_back(vix::cli::errors::template_rules::makeIncompleteTypeRule());
47+
templateRules_.push_back(vix::cli::errors::template_rules::makeNoViableConversionRule());
48+
templateRules_.push_back(vix::cli::errors::template_rules::makeConstQualifierRule());
49+
templateRules_.push_back(vix::cli::errors::template_rules::makeInvalidReferenceBindingRule());
50+
templateRules_.push_back(vix::cli::errors::template_rules::makeInvalidInitializerListRule());
51+
templateRules_.push_back(vix::cli::errors::template_rules::makeNarrowingConversionRule());
52+
templateRules_.push_back(vix::cli::errors::template_rules::makeMissingBeginEndRule());
53+
templateRules_.push_back(vix::cli::errors::template_rules::makeAmbiguousOverloadRule());
54+
templateRules_.push_back(vix::cli::errors::template_rules::makeOperatorNotFoundRule());
55+
templateRules_.push_back(vix::cli::errors::template_rules::makeAllocatorValueTypeMismatchRule());
56+
templateRules_.push_back(vix::cli::errors::template_rules::makeTupleVariantAccessRule());
57+
templateRules_.push_back(vix::cli::errors::template_rules::makeInvalidUseOfVoidRule());
58+
59+
// Lifetime / OOP / slicing family
3160
templateRules_.push_back(vix::cli::errors::template_rules::makeLambdaCaptureLifetimeRule());
3261
templateRules_.push_back(vix::cli::errors::template_rules::makeNonVirtualDestructorDeleteRule());
3362
templateRules_.push_back(vix::cli::errors::template_rules::makeObjectSlicingRule());
3463
templateRules_.push_back(vix::cli::errors::template_rules::makeBadOverrideRule());
3564
templateRules_.push_back(vix::cli::errors::template_rules::makeInvalidDowncastRule());
65+
66+
// Coroutines family (always late, very specific signals)
3667
templateRules_.push_back(vix::cli::errors::template_rules::makeCoroutineReturnTypeRule());
3768
templateRules_.push_back(vix::cli::errors::template_rules::makeMissingCoReturnRule());
3869
templateRules_.push_back(vix::cli::errors::template_rules::makeInvalidAwaitableRule());
3970
templateRules_.push_back(vix::cli::errors::template_rules::makeNoMemberAwaitReadyRule());
4071
templateRules_.push_back(vix::cli::errors::template_rules::makeNoMemberAwaitSuspendRule());
4172
templateRules_.push_back(vix::cli::errors::template_rules::makeNoMemberAwaitResumeRule());
4273
templateRules_.push_back(vix::cli::errors::template_rules::makeInvalidPromiseTypeRule());
43-
templateRules_.push_back(vix::cli::errors::template_rules::makeSubstitutionFailureRule());
4474

4575
// Beginner / syntax / common mistakes
4676
rules_.push_back(makeCoutNotDeclaredRule());
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
*
3+
* @file AllocatorValueTypeMismatchRule.cpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2025, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*
13+
*/
14+
#include <vix/cli/errors/template/ITemplateErrorRule.hpp>
15+
#include <vix/cli/errors/CodeFrame.hpp>
16+
17+
#include <iostream>
18+
#include <memory>
19+
#include <string>
20+
21+
#include <vix/cli/Style.hpp>
22+
23+
using namespace vix::cli::style;
24+
25+
namespace vix::cli::errors::template_rules
26+
{
27+
namespace
28+
{
29+
bool icontains(const std::string &text, const std::string &needle)
30+
{
31+
if (needle.empty())
32+
return true;
33+
34+
auto lower = [](unsigned char c) -> char
35+
{
36+
if (c >= 'A' && c <= 'Z')
37+
return static_cast<char>(c + ('a' - 'A'));
38+
return static_cast<char>(c);
39+
};
40+
41+
if (text.size() < needle.size())
42+
return false;
43+
44+
for (std::size_t i = 0; i + needle.size() <= text.size(); ++i)
45+
{
46+
bool ok = true;
47+
for (std::size_t j = 0; j < needle.size(); ++j)
48+
{
49+
if (lower(static_cast<unsigned char>(text[i + j])) !=
50+
lower(static_cast<unsigned char>(needle[j])))
51+
{
52+
ok = false;
53+
break;
54+
}
55+
}
56+
if (ok)
57+
return true;
58+
}
59+
return false;
60+
}
61+
62+
std::string choose_hint(const std::string &message)
63+
{
64+
(void)message;
65+
return "make the allocator value_type match the container element type";
66+
}
67+
} // namespace
68+
69+
class AllocatorValueTypeMismatchRule final : public ITemplateErrorRule
70+
{
71+
public:
72+
bool match(const vix::cli::errors::CompilerError &err) const override
73+
{
74+
const std::string &message = err.message;
75+
76+
if (icontains(message, "allocator value_type must be same type"))
77+
return true;
78+
79+
if (icontains(message, "must have the same value_type as its allocator"))
80+
return true;
81+
82+
if (icontains(message, "allocator_traits") &&
83+
icontains(message, "value_type"))
84+
{
85+
return true;
86+
}
87+
88+
return false;
89+
}
90+
91+
bool handle(
92+
const vix::cli::errors::CompilerError &err,
93+
const vix::cli::errors::ErrorContext &ctx) const override
94+
{
95+
std::cerr << RED
96+
<< "error: allocator value_type mismatch"
97+
<< RESET << "\n";
98+
99+
printCodeFrame(err, ctx);
100+
101+
std::cerr << YELLOW
102+
<< "hint: "
103+
<< RESET
104+
<< choose_hint(err.message)
105+
<< "\n";
106+
107+
std::cerr << GREEN
108+
<< "at: "
109+
<< RESET
110+
<< err.file << ":" << err.line << ":" << err.column
111+
<< "\n";
112+
113+
return true;
114+
}
115+
};
116+
117+
std::unique_ptr<ITemplateErrorRule> makeAllocatorValueTypeMismatchRule()
118+
{
119+
return std::make_unique<AllocatorValueTypeMismatchRule>();
120+
}
121+
} // namespace vix::cli::errors::template_rules
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/**
2+
*
3+
* @file AmbiguousOverloadRule.cpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2025, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*
13+
*/
14+
#include <vix/cli/errors/template/ITemplateErrorRule.hpp>
15+
#include <vix/cli/errors/CodeFrame.hpp>
16+
17+
#include <iostream>
18+
#include <memory>
19+
#include <string>
20+
21+
#include <vix/cli/Style.hpp>
22+
23+
using namespace vix::cli::style;
24+
25+
namespace vix::cli::errors::template_rules
26+
{
27+
namespace
28+
{
29+
bool icontains(const std::string &text, const std::string &needle)
30+
{
31+
if (needle.empty())
32+
return true;
33+
34+
auto lower = [](unsigned char c) -> char
35+
{
36+
if (c >= 'A' && c <= 'Z')
37+
return static_cast<char>(c + ('a' - 'A'));
38+
return static_cast<char>(c);
39+
};
40+
41+
if (text.size() < needle.size())
42+
return false;
43+
44+
for (std::size_t i = 0; i + needle.size() <= text.size(); ++i)
45+
{
46+
bool ok = true;
47+
for (std::size_t j = 0; j < needle.size(); ++j)
48+
{
49+
if (lower(static_cast<unsigned char>(text[i + j])) !=
50+
lower(static_cast<unsigned char>(needle[j])))
51+
{
52+
ok = false;
53+
break;
54+
}
55+
}
56+
if (ok)
57+
return true;
58+
}
59+
return false;
60+
}
61+
62+
std::string choose_hint(const std::string &message)
63+
{
64+
(void)message;
65+
return "make the call explicit by casting arguments, qualifying the overload, "
66+
"or removing competing overloads";
67+
}
68+
} // namespace
69+
70+
class AmbiguousOverloadRule final : public ITemplateErrorRule
71+
{
72+
public:
73+
bool match(const vix::cli::errors::CompilerError &err) const override
74+
{
75+
const std::string &message = err.message;
76+
77+
if (icontains(message, "is ambiguous"))
78+
return true;
79+
80+
if (icontains(message, "ambiguous overload"))
81+
return true;
82+
83+
if (icontains(message, "ambiguous conversion"))
84+
return true;
85+
86+
return false;
87+
}
88+
89+
bool handle(
90+
const vix::cli::errors::CompilerError &err,
91+
const vix::cli::errors::ErrorContext &ctx) const override
92+
{
93+
std::cerr << RED
94+
<< "error: ambiguous overload"
95+
<< RESET << "\n";
96+
97+
printCodeFrame(err, ctx);
98+
99+
std::cerr << YELLOW
100+
<< "hint: "
101+
<< RESET
102+
<< choose_hint(err.message)
103+
<< "\n";
104+
105+
std::cerr << GREEN
106+
<< "at: "
107+
<< RESET
108+
<< err.file << ":" << err.line << ":" << err.column
109+
<< "\n";
110+
111+
return true;
112+
}
113+
};
114+
115+
std::unique_ptr<ITemplateErrorRule> makeAmbiguousOverloadRule()
116+
{
117+
return std::make_unique<AmbiguousOverloadRule>();
118+
}
119+
} // namespace vix::cli::errors::template_rules

0 commit comments

Comments
 (0)