Remove memory leaks of Rule instances.
All Rule instances were leaked, so ensure they
are owned by the BindingEnv they belong to, and
deleted appropriately.
+ Add Rule::is_phony() method.
Fuchsia-Topic: persistent-mode
Original-Change-Id: I4a6db65e250ce70eaa03922fa99bbc6cc160f009
Change-Id: I97af0c10cf882a6cf30c3c1c2ba97b4bacde5188
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/github.com/ninja-build/ninja/+/977217
Reviewed-by: David Fang <fangism@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/src/eval_env.cc b/src/eval_env.cc
index 796a326..675bb83 100644
--- a/src/eval_env.cc
+++ b/src/eval_env.cc
@@ -31,22 +31,22 @@
bindings_[key] = val;
}
-void BindingEnv::AddRule(const Rule* rule) {
+void BindingEnv::AddRule(Rule* rule) {
assert(LookupRuleCurrentScope(rule->name()) == NULL);
- rules_[rule->name()] = rule;
+ rules_.emplace(rule->name(), std::unique_ptr<Rule>(rule));
}
const Rule* BindingEnv::LookupRuleCurrentScope(const string& rule_name) {
- map<string, const Rule*>::iterator i = rules_.find(rule_name);
- if (i == rules_.end())
+ auto it = rules_.find(rule_name);
+ if (it == rules_.end())
return NULL;
- return i->second;
+ return it->second.get();
}
const Rule* BindingEnv::LookupRule(const string& rule_name) {
- map<string, const Rule*>::iterator i = rules_.find(rule_name);
- if (i != rules_.end())
- return i->second;
+ auto it = rules_.find(rule_name);
+ if (it != rules_.end())
+ return it->second.get();
if (parent_)
return parent_->LookupRule(rule_name);
return NULL;
@@ -78,10 +78,6 @@
var == "msvc_deps_prefix";
}
-const map<string, const Rule*>& BindingEnv::GetRules() const {
- return rules_;
-}
-
string BindingEnv::LookupWithFallback(const string& var,
const EvalString* eval,
Env* env) {
diff --git a/src/eval_env.h b/src/eval_env.h
index 677dc21..2c69d94 100644
--- a/src/eval_env.h
+++ b/src/eval_env.h
@@ -16,6 +16,7 @@
#define NINJA_EVAL_ENV_H_
#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -57,10 +58,13 @@
/// An invocable build command and associated metadata (description, etc.).
struct Rule {
- explicit Rule(const std::string& name) : name_(name) {}
+ Rule(StringPiece name)
+ : name_(name.str_, name.len_), is_phony_(name_ == "phony") {}
const std::string& name() const { return name_; }
+ bool is_phony() const { return is_phony_; }
+
void AddBinding(const std::string& key, const EvalString& val);
static bool IsReservedBinding(const std::string& var);
@@ -72,6 +76,7 @@
friend struct ManifestParser;
std::string name_;
+ bool is_phony_;
typedef std::map<std::string, EvalString> Bindings;
Bindings bindings_;
};
@@ -82,13 +87,22 @@
BindingEnv() : parent_(NULL) {}
explicit BindingEnv(BindingEnv* parent) : parent_(parent) {}
+ BindingEnv(const BindingEnv&) = delete;
+ BindingEnv& operator=(const BindingEnv&) = delete;
+
+ BindingEnv(BindingEnv&&) noexcept = default;
+ BindingEnv& operator=(BindingEnv&&) noexcept = default;
+
virtual ~BindingEnv() {}
virtual std::string LookupVariable(const std::string& var);
- void AddRule(const Rule* rule);
+ /// Add a new rule, takes ownership.
+ void AddRule(Rule* rule);
const Rule* LookupRule(const std::string& rule_name);
const Rule* LookupRuleCurrentScope(const std::string& rule_name);
- const std::map<std::string, const Rule*>& GetRules() const;
+
+ using RuleMapType = std::map<std::string, std::unique_ptr<const Rule>>;
+ const RuleMapType& GetRules() const { return rules_; }
void AddBinding(const std::string& key, const std::string& val);
@@ -102,7 +116,7 @@
private:
std::map<std::string, std::string> bindings_;
- std::map<std::string, const Rule*> rules_;
+ RuleMapType rules_;
BindingEnv* parent_;
};
diff --git a/src/graph.cc b/src/graph.cc
index 2132388..2ea491e 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -589,7 +589,7 @@
}
bool Edge::is_phony() const {
- return rule_ == &State::kPhonyRule;
+ return rule_->is_phony();
}
bool Edge::use_console() const {
diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc
index c4b2980..c52925c 100644
--- a/src/manifest_parser.cc
+++ b/src/manifest_parser.cc
@@ -143,7 +143,7 @@
if (env_->LookupRuleCurrentScope(name) != NULL)
return lexer_.Error("duplicate rule '" + name + "'", err);
- Rule* rule = new Rule(name); // XXX scoped_ptr
+ auto rule = std::unique_ptr<Rule>(new Rule(name));
while (lexer_.PeekToken(Lexer::INDENT)) {
string key;
@@ -169,7 +169,7 @@
if (rule->bindings_["command"].empty())
return lexer_.Error("expected 'command =' line", err);
- env_->AddRule(rule);
+ env_->AddRule(rule.release());
return true;
}
diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc
index c5a1fe8..e41d8ae 100644
--- a/src/manifest_parser_test.cc
+++ b/src/manifest_parser_test.cc
@@ -51,7 +51,7 @@
"build result: cat in_1.cc in-2.O\n"));
ASSERT_EQ(3u, state.bindings_.GetRules().size());
- const Rule* rule = state.bindings_.GetRules().begin()->second;
+ const Rule* rule = state.bindings_.GetRules().begin()->second.get();
EXPECT_EQ("cat", rule->name());
EXPECT_EQ("[cat ][$in][ > ][$out]",
rule->GetBinding("command")->Serialize());
@@ -84,7 +84,7 @@
" #comment\n"));
ASSERT_EQ(2u, state.bindings_.GetRules().size());
- const Rule* rule = state.bindings_.GetRules().begin()->second;
+ const Rule* rule = state.bindings_.GetRules().begin()->second.get();
EXPECT_EQ("cat", rule->name());
Edge* edge = state.GetNode("result", 0)->in_edge();
EXPECT_TRUE(edge->GetBindingBool("restat"));
@@ -117,7 +117,7 @@
" rspfile=out.rsp\n"));
ASSERT_EQ(2u, state.bindings_.GetRules().size());
- const Rule* rule = state.bindings_.GetRules().begin()->second;
+ const Rule* rule = state.bindings_.GetRules().begin()->second.get();
EXPECT_EQ("cat_rsp", rule->name());
EXPECT_EQ("[cat ][$rspfile][ > ][$out]",
rule->GetBinding("command")->Serialize());
@@ -134,7 +134,7 @@
" rspfile=out.rsp\n"));
ASSERT_EQ(2u, state.bindings_.GetRules().size());
- const Rule* rule = state.bindings_.GetRules().begin()->second;
+ const Rule* rule = state.bindings_.GetRules().begin()->second.get();
EXPECT_EQ("cat_rsp", rule->name());
EXPECT_EQ("[cat ][$in_newline][ > ][$out]",
rule->GetBinding("command")->Serialize());
@@ -195,7 +195,7 @@
" d e f\n"));
ASSERT_EQ(2u, state.bindings_.GetRules().size());
- const Rule* rule = state.bindings_.GetRules().begin()->second;
+ const Rule* rule = state.bindings_.GetRules().begin()->second.get();
EXPECT_EQ("link", rule->name());
EXPECT_EQ("[foo bar baz]", rule->GetBinding("command")->Serialize());
}
diff --git a/src/ninja.cc b/src/ninja.cc
index 7ccf164..c08b20e 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -658,14 +658,12 @@
// Print rules
- typedef map<string, const Rule*> Rules;
- const Rules& rules = state_.bindings_.GetRules();
- for (Rules::const_iterator i = rules.begin(); i != rules.end(); ++i) {
- printf("%s", i->first.c_str());
+ for (const auto& pair : state_.bindings_.GetRules()) {
+ printf("%s", pair.first.c_str());
if (print_description) {
- const Rule* rule = i->second;
- const EvalString* description = rule->GetBinding("description");
- if (description != NULL) {
+ const Rule* rule = pair.second.get();
+ const EvalString* description = rule->GetBinding("description");
+ if (description != NULL) {
printf(": %s", description->Unparse().c_str());
}
}
diff --git a/src/state.cc b/src/state.cc
index 39f0dff..cc78d03 100644
--- a/src/state.cc
+++ b/src/state.cc
@@ -67,10 +67,9 @@
delayed_.clear();
}
-const Rule State::kPhonyRule("phony");
-
State::State() {
- bindings_.AddRule(&kPhonyRule);
+ phony_rule_ = new Rule("phony");
+ bindings_.AddRule(phony_rule_);
default_pool_ = new Pool("", 0);
console_pool_ = new Pool("console", 1);
AddPool(default_pool_);
diff --git a/src/state.h b/src/state.h
index b8ff095..958463b 100644
--- a/src/state.h
+++ b/src/state.h
@@ -100,8 +100,6 @@
/// Global state (file status) for a single run.
struct State {
- static const Rule kPhonyRule;
-
State();
~State();
@@ -124,6 +122,12 @@
/// implicitly.
Pool* console_pool() const;
+ /// Return pointer to phony rule. This one is always created implicitly.
+ const Rule* phony_rule() const { return phony_rule_; }
+
+ /// Allocate new Rule instance.
+ Rule* NewRule(StringPiece name);
+
Edge* AddEdge(const Rule* rule);
Node* GetNode(StringPiece path, uint64_t slash_bits);
@@ -167,6 +171,7 @@
/// NOTE: This owns all Edge instances.
std::vector<Edge*> edges_;
+ Rule* phony_rule_ = nullptr;
BindingEnv bindings_;
std::vector<Node*> defaults_;
};