Skip to content

Commit

Permalink
Require string literals for format strings (sorbet#1603)
Browse files Browse the repository at this point in the history
* Get started on making formatting error not a thing

* Add an include

* Use a literal

* Use a literal and a fmt::format
  • Loading branch information
DarkDimius authored and azdavis committed Aug 15, 2019
1 parent e098f59 commit 09fc625
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 26 deletions.
20 changes: 20 additions & 0 deletions common/ConstExprStr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef SORBET_CONSTEXPRSTR_H
#define SORBET_CONSTEXPRSTR_H
#include <cstddef> // std::size_t

namespace sorbet {
struct ConstExprStr {
char const *str;
std::size_t size;

// can only construct from a char[] literal
template <std::size_t N>
constexpr ConstExprStr(char const (&s)[N])
: str(s), size(N - 1) // not count the trailing null
{}

ConstExprStr() = delete;
};
}; // namespace sorbet

#endif
14 changes: 1 addition & 13 deletions common/Counters.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#ifndef SORBET_COUNTERS_H
#define SORBET_COUNTERS_H
#include "common/ConstExprStr.h"
#include "common/common.h"
#include <chrono>
#include <string>
Expand Down Expand Up @@ -28,19 +29,6 @@ constexpr bool enable_counters = debug_mode;
// units (but not necessarily between translation units), but this can't be
// relied upon, so we canonicalize strings when retrieving statistics.

struct ConstExprStr {
char const *str;
std::size_t size;

// can only construct from a char[] literal
template <std::size_t N>
constexpr ConstExprStr(char const (&s)[N])
: str(s), size(N - 1) // not count the trailing null
{}

ConstExprStr() = delete;
};

struct CounterImpl;

// forward declarations for classes that need private access to the counter
Expand Down
14 changes: 7 additions & 7 deletions core/Error.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#ifndef SORBET_REPORTER_H
#define SORBET_REPORTER_H

#include "common/ConstExprStr.h"
#include "core/AutocorrectSuggestion.h"
#include "core/Loc.h"
#include "core/StrictLevel.h"
Expand Down Expand Up @@ -146,20 +146,20 @@ class ErrorBuilder {
return state == State::WillBuild;
}
void addErrorSection(ErrorSection &&section);
template <typename... Args> void addErrorLine(Loc loc, std::string_view msg, const Args &... args) {
std::string formatted = ErrorColors::format(msg, args...);
template <typename... Args> void addErrorLine(Loc loc, ConstExprStr msg, const Args &... args) {
std::string formatted = ErrorColors::format(msg.str, args...);
addErrorSection(ErrorSection({ErrorLine(loc, formatted)}));
}

template <typename... Args> void setHeader(std::string_view msg, const Args &... args) {
std::string formatted = ErrorColors::format(msg, args...);
template <typename... Args> void setHeader(ConstExprStr msg, const Args &... args) {
std::string formatted = ErrorColors::format(msg.str, args...);
_setHeader(move(formatted));
}

void addAutocorrect(AutocorrectSuggestion &&autocorrect);
template <typename... Args>
void replaceWith(const std::string &title, Loc loc, std::string_view replacement, const Args &... args) {
std::string formatted = fmt::format(replacement, args...);
void replaceWith(const std::string &title, Loc loc, ConstExprStr replacement, const Args &... args) {
std::string formatted = fmt::format(replacement.str, args...);
addAutocorrect(AutocorrectSuggestion{title, {AutocorrectSuggestion::Edit{loc, move(formatted)}}});
}

Expand Down
2 changes: 1 addition & 1 deletion core/types/calls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ class T_must : public IntrinsicMethod {
if (auto e = ctx.state.beginError(loc, errors::Infer::InvalidCast)) {
e.setHeader("T.must(): Expected a `T.nilable` type, got: `{}`", args.args[0]->type->show(ctx));
const auto locWithoutTMust = Loc{loc.file(), loc.beginPos() + 7, loc.endPos() - 1};
e.replaceWith("Remove the T.must", loc, locWithoutTMust.source(ctx));
e.replaceWith("Remove the T.must", loc, "{}", locWithoutTMust.source(ctx));
}
}
res.returnType = move(ret);
Expand Down
5 changes: 3 additions & 2 deletions main/options/options.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#ifndef RUBY_TYPER_OPTIONS_H
#define RUBY_TYPER_OPTIONS_H
#include "common/ConstExprStr.h"
#include "common/FileSystem.h"
#include "common/common.h"
#include "core/StrictLevel.h"
Expand All @@ -22,8 +23,8 @@ class PrinterConfig {
bool supportsFlush = false;

void print(const std::string_view &contents) const;
template <typename... Args> void fmt(const std::string &msg, const Args &... args) const {
print(fmt::format(msg, args...));
template <typename... Args> void fmt(const ConstExprStr msg, const Args &... args) const {
print(fmt::format(msg.str, args...));
}
void flush();

Expand Down
4 changes: 1 addition & 3 deletions parser/Parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,10 @@ class ErrorToError {
default:
Exception::notImplemented();
}
string msg("Parse {}: ");
msg.append(dclassStrings[(int)diag.error_class()]);
core::Loc loc(file, translatePos(diag.location().beginPos, maxOff - 1),
translatePos(diag.location().endPos, maxOff));
if (auto e = gs.beginError(loc, core::errors::Parser::ParserError)) {
e.setHeader(msg, level, diag.data());
e.setHeader("Parse {}: {}", level, fmt::format(dclassStrings[(int)diag.error_class()], diag.data()));
}
}
}
Expand Down

0 comments on commit 09fc625

Please sign in to comment.