aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/expr.cc2
-rw-r--r--src/find.cc2
-rw-r--r--src/func.cc57
-rw-r--r--src/strutil.cc5
-rw-r--r--src/strutil.h5
-rw-r--r--src/symtab.cc2
-rw-r--r--src/var.cc35
-rw-r--r--src/var.h9
-rw-r--r--testcase/var_visibility_prefix_conflict.mk16
-rw-r--r--testcase/var_visibility_prefix_implicit_define.mk6
-rw-r--r--testcase/var_visibility_prefix_invalid_file_four.mk16
-rw-r--r--testcase/var_visibility_prefix_invalid_file_one.mk23
-rw-r--r--testcase/var_visibility_prefix_invalid_file_two.mk16
-rw-r--r--testcase/var_visibility_prefix_invalid_prefix_four.mk8
-rw-r--r--testcase/var_visibility_prefix_invalid_prefix_one.mk8
-rw-r--r--testcase/var_visibility_prefix_invalid_prefix_three.mk9
-rw-r--r--testcase/var_visibility_prefix_invalid_prefix_two.mk8
17 files changed, 224 insertions, 3 deletions
diff --git a/src/expr.cc b/src/expr.cc
index e3a8629..102bfdf 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -146,6 +146,7 @@ class SymRef : public Value {
Var* v = ev->LookupVarForEval(name_);
v->Used(ev, name_);
v->Eval(ev, s);
+ v->CheckCurrentReferencingFile(ev->loc(), name_.c_str());
ev->VarEvalComplete(name_);
}
@@ -176,6 +177,7 @@ class VarRef : public Value {
Var* v = ev->LookupVarForEval(sym);
v->Used(ev, sym);
v->Eval(ev, s);
+ v->CheckCurrentReferencingFile(ev->loc(), name.c_str());
ev->VarEvalComplete(sym);
}
diff --git a/src/find.cc b/src/find.cc
index 4e81851..0a43527 100644
--- a/src/find.cc
+++ b/src/find.cc
@@ -28,7 +28,7 @@
#include <string_view>
#include <vector>
-//#undef NOLOG
+// #undef NOLOG
#include "fileutil.h"
#include "log.h"
diff --git a/src/func.cc b/src/func.cc
index 75a7cb6..b3e544c 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -27,6 +27,7 @@
#include <algorithm>
#include <iterator>
#include <memory>
+#include <sstream>
#include <unordered_map>
#include "eval.h"
@@ -510,7 +511,7 @@ void EvalFunc(const std::vector<Value*>& args, Evaluator* ev, std::string*) {
}
}
-//#define TEST_FIND_EMULATOR
+// #define TEST_FIND_EMULATOR
// A hack for Android build. We need to evaluate things like $((3+4))
// when we emit ninja file, because the result of such expressions
@@ -656,6 +657,59 @@ void ShellFuncNoRerun(const std::vector<Value*>& args,
ShellStatusVar::SetValue(returnCode);
}
+void VarVisibilityFunc(const std::vector<Value*>& args,
+ Evaluator* ev,
+ std::string*) {
+ std::string arg = args[0]->Eval(ev);
+ std::vector<std::string> prefixes;
+
+ std::stringstream ss(args[1]->Eval(ev));
+ std::string prefix;
+ while (ss >> prefix) {
+ if (HasPrefix(prefix, "/")) {
+ ERROR_LOC(ev->loc(), "Visibility prefix should not start with /");
+ }
+ if (HasPrefix(prefix, "../")) {
+ ERROR_LOC(ev->loc(), "Visibility prefix should not start with ../");
+ }
+
+ std::string normalizedPrefix = prefix;
+ NormalizePath(&normalizedPrefix);
+ if (prefix != normalizedPrefix) {
+ ERROR_LOC(ev->loc(),
+ "Visibility prefix %s is not normalized. Normalized prefix: %s",
+ prefix.c_str(), normalizedPrefix.c_str());
+ }
+
+ // one visibility prefix cannot be the prefix of another visibility prefix
+ for (std::vector<std::string>::iterator it = prefixes.begin();
+ it != prefixes.end(); ++it) {
+ if (HasPathPrefix(*it, prefix)) {
+ ERROR_LOC(ev->loc(),
+ "Visibility prefix %s is the prefix of another visibility "
+ "prefix %s",
+ prefix.c_str(), it->c_str());
+ } else if (HasPathPrefix(prefix, *it)) {
+ ERROR_LOC(ev->loc(),
+ "Visibility prefix %s is the prefix of another visibility "
+ "prefix %s",
+ it->c_str(), prefix.c_str());
+ }
+ }
+
+ prefixes.push_back(prefix);
+ }
+
+ Symbol sym = Intern(arg);
+ Var* v = ev->PeekVar(sym);
+ // If variable is not defined, create an empty variable.
+ if (!v->IsDefined()) {
+ v = new SimpleVar(VarOrigin::FILE, ev->CurrentFrame(), ev->loc());
+ sym.SetGlobalVar(v, false, nullptr);
+ }
+ v->SetVisibilityPrefix(prefixes, sym.c_str());
+}
+
void CallFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
static const Symbol tmpvar_names[] = {
Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
@@ -1149,6 +1203,7 @@ static const std::unordered_map<std::string_view, FuncInfo> g_func_info_map = {
ENTRY("KATI_shell_no_rerun", &ShellFuncNoRerun, 1, 1, false, false),
ENTRY("KATI_foreach_sep", &ForeachWithSepFunc, 4, 4, false, false),
ENTRY("KATI_file_no_rerun", &FileFuncNoRerun, 2, 1, false, false),
+ ENTRY("KATI_visibility_prefix", &VarVisibilityFunc, 2, 1, false, false),
};
} // namespace
diff --git a/src/strutil.cc b/src/strutil.cc
index 149c729..08c04cf 100644
--- a/src/strutil.cc
+++ b/src/strutil.cc
@@ -110,6 +110,11 @@ bool HasPrefix(std::string_view str, std::string_view prefix) {
return size_diff >= 0 && str.substr(0, prefix.size()) == prefix;
}
+bool HasPathPrefix(std::string_view str, std::string_view prefix) {
+ return HasPrefix(str, prefix) &&
+ (str.size() == prefix.size() || str.at(prefix.size()) == '/');
+}
+
bool HasSuffix(std::string_view str, std::string_view suffix) {
ssize_t size_diff = str.size() - suffix.size();
return size_diff >= 0 && str.substr(size_diff) == suffix;
diff --git a/src/strutil.h b/src/strutil.h
index bd71c1b..0045875 100644
--- a/src/strutil.h
+++ b/src/strutil.h
@@ -80,6 +80,11 @@ inline std::string JoinStrings(std::vector<String> v, const char* sep) {
bool HasPrefix(std::string_view str, std::string_view prefix);
+// Checks path-like prefixes. str and prefix and both considered as strings
+// that represent "path".
+// e.g. str "foo/bar" has path prefix "foo" but doesn't have path prefix "fo".
+bool HasPathPrefix(std::string_view str, std::string_view prefix);
+
bool HasSuffix(std::string_view str, std::string_view suffix);
bool HasWord(std::string_view str, std::string_view w);
diff --git a/src/symtab.cc b/src/symtab.cc
index 0ba1213..57c1417 100644
--- a/src/symtab.cc
+++ b/src/symtab.cc
@@ -14,7 +14,7 @@
// +build ignore
-//#define ENABLE_TID_CHECK
+// #define ENABLE_TID_CHECK
#include "symtab.h"
diff --git a/src/var.cc b/src/var.cc
index 0f1cb05..9907409 100644
--- a/src/var.cc
+++ b/src/var.cc
@@ -85,6 +85,41 @@ void Var::Used(Evaluator* ev, const Symbol& sym) const {
}
}
+void Var::SetVisibilityPrefix(const std::vector<std::string>& prefixes,
+ const char* name) {
+ const std::vector<std::string>& current_prefixes = VisibilityPrefix();
+ if (current_prefixes.size() == 0) {
+ visibility_prefix_ = prefixes;
+ } else if (current_prefixes != prefixes) {
+ ERROR("Visibility prefix conflict on variable: %s", name);
+ }
+}
+
+void Var::CheckCurrentReferencingFile(Loc loc, const char* name) {
+ const std::vector<std::string>& prefixes = VisibilityPrefix();
+ if (prefixes.size() == 0) {
+ return;
+ }
+ bool valid = false;
+ for (const std::string& prefix : prefixes) {
+ if (HasPathPrefix(loc.filename, prefix)) {
+ valid = true;
+ break;
+ }
+ }
+ if (!valid) {
+ std::string prefixesString;
+ for (const std::string& p : prefixes) {
+ prefixesString += (p + "\n");
+ }
+ prefixesString.pop_back();
+ ERROR(
+ "%s is not a valid file to reference variable %s. Line #%d.\nValid "
+ "file prefixes:\n%s",
+ loc.filename, name, loc.lineno, prefixesString.c_str());
+ }
+}
+
const char* Var::diagnostic_message_text() const {
auto it = diagnostic_messages_.find(this);
return it == diagnostic_messages_.end() ? "" : it->second.c_str();
diff --git a/src/var.h b/src/var.h
index 0e0972f..a1c9096 100644
--- a/src/var.h
+++ b/src/var.h
@@ -73,6 +73,13 @@ class Var : public Evaluable {
bool SelfReferential() const { return self_referential_; }
void SetSelfReferential() { self_referential_ = true; }
+ const std::vector<std::string>& VisibilityPrefix() const {
+ return visibility_prefix_;
+ }
+ void SetVisibilityPrefix(const std::vector<std::string>& prefixes,
+ const char* name);
+ void CheckCurrentReferencingFile(Loc loc, const char* name);
+
const std::string& DeprecatedMessage() const;
// This variable was used (either written or read from)
@@ -101,6 +108,8 @@ class Var : public Evaluable {
const char* diagnostic_message_text() const;
static std::unordered_map<const Var*, std::string> diagnostic_messages_;
+
+ std::vector<std::string> visibility_prefix_;
};
class SimpleVar : public Var {
diff --git a/testcase/var_visibility_prefix_conflict.mk b/testcase/var_visibility_prefix_conflict.mk
new file mode 100644
index 0000000..265d020
--- /dev/null
+++ b/testcase/var_visibility_prefix_conflict.mk
@@ -0,0 +1,16 @@
+FOO := foo
+BAR := bar
+PREFIX := pone/ptwo
+
+$(KATI_visibility_prefix FOO, pone/ptwo baz)
+$(KATI_visibility_prefix FOO, $(PREFIX) baz)
+
+$(KATI_visibility_prefix BAR, pone/ptwo baz)
+$(KATI_visibility_prefix BAR, baz $(PREFIX))
+
+ifndef KATI
+$(info Visibility prefix conflict on variable: BAR)
+endif
+
+test:
+ @:
diff --git a/testcase/var_visibility_prefix_implicit_define.mk b/testcase/var_visibility_prefix_implicit_define.mk
new file mode 100644
index 0000000..144fdf6
--- /dev/null
+++ b/testcase/var_visibility_prefix_implicit_define.mk
@@ -0,0 +1,6 @@
+$(KATI_visibility_prefix FOO, Makefile)
+
+BAR := $(FOO)
+
+test:
+ echo '$(BAR)'
diff --git a/testcase/var_visibility_prefix_invalid_file_four.mk b/testcase/var_visibility_prefix_invalid_file_four.mk
new file mode 100644
index 0000000..de00dab
--- /dev/null
+++ b/testcase/var_visibility_prefix_invalid_file_four.mk
@@ -0,0 +1,16 @@
+$(KATI_visibility_prefix BAR, bar)
+FOO = $(BAR) # this should be okay, since it's not evaluated
+BAZ := $(FOO)
+
+define ERROR_MSG
+Makefile is not a valid file to reference variable BAR. Line #3.
+Valid file prefixes:
+bar
+endef
+
+ifndef KATI
+$(info $(ERROR_MSG))
+endif
+
+test:
+ @:
diff --git a/testcase/var_visibility_prefix_invalid_file_one.mk b/testcase/var_visibility_prefix_invalid_file_one.mk
new file mode 100644
index 0000000..ea97905
--- /dev/null
+++ b/testcase/var_visibility_prefix_invalid_file_one.mk
@@ -0,0 +1,23 @@
+FOO := foo
+BAR := bar
+$(KATI_visibility_prefix FOO, Makefile)
+$(KATI_visibility_prefix BAR, )
+$(KATI_visibility_prefix BAZ, baz)
+
+VAR0 := $(FOO)
+VAR1 := $(BAR)
+VAR2 := $$(BAZ)
+VAR3 := $($(BAZ))
+
+define ERROR_MSG
+Makefile is not a valid file to reference variable BAZ. Line #10.
+Valid file prefixes:
+baz
+endef
+
+ifndef KATI
+$(info $(ERROR_MSG))
+endif
+
+test:
+ @:
diff --git a/testcase/var_visibility_prefix_invalid_file_two.mk b/testcase/var_visibility_prefix_invalid_file_two.mk
new file mode 100644
index 0000000..28f84a6
--- /dev/null
+++ b/testcase/var_visibility_prefix_invalid_file_two.mk
@@ -0,0 +1,16 @@
+$(KATI_visibility_prefix BAR, bar)
+FOO := BAR
+BAZ := $($(FOO))
+
+define ERROR_MSG
+Makefile is not a valid file to reference variable BAR. Line #3.
+Valid file prefixes:
+bar
+endef
+
+ifndef KATI
+$(info $(ERROR_MSG))
+endif
+
+test:
+ @:
diff --git a/testcase/var_visibility_prefix_invalid_prefix_four.mk b/testcase/var_visibility_prefix_invalid_prefix_four.mk
new file mode 100644
index 0000000..b8a45b3
--- /dev/null
+++ b/testcase/var_visibility_prefix_invalid_prefix_four.mk
@@ -0,0 +1,8 @@
+$(KATI_visibility_prefix FOO, foo/)
+
+ifndef KATI
+$(info Makefile:1: Visibility prefix foo/ is not normalized. Normalized prefix: foo)
+endif
+
+test:
+ @:
diff --git a/testcase/var_visibility_prefix_invalid_prefix_one.mk b/testcase/var_visibility_prefix_invalid_prefix_one.mk
new file mode 100644
index 0000000..65a2f3a
--- /dev/null
+++ b/testcase/var_visibility_prefix_invalid_prefix_one.mk
@@ -0,0 +1,8 @@
+$(KATI_visibility_prefix FOO, /foo)
+
+ifndef KATI
+$(info Makefile:1: Visibility prefix should not start with /)
+endif
+
+test:
+ @:
diff --git a/testcase/var_visibility_prefix_invalid_prefix_three.mk b/testcase/var_visibility_prefix_invalid_prefix_three.mk
new file mode 100644
index 0000000..3e599f0
--- /dev/null
+++ b/testcase/var_visibility_prefix_invalid_prefix_three.mk
@@ -0,0 +1,9 @@
+$(KATI_visibility_prefix FOO, foo fo) # no error, different path prefixes
+$(KATI_visibility_prefix Bar, bar/baz bar)
+
+ifndef KATI
+$(info Makefile:2: Visibility prefix bar is the prefix of another visibility prefix bar/baz)
+endif
+
+test:
+ @:
diff --git a/testcase/var_visibility_prefix_invalid_prefix_two.mk b/testcase/var_visibility_prefix_invalid_prefix_two.mk
new file mode 100644
index 0000000..a208c94
--- /dev/null
+++ b/testcase/var_visibility_prefix_invalid_prefix_two.mk
@@ -0,0 +1,8 @@
+$(KATI_visibility_prefix FOO, foo ../foo)
+
+ifndef KATI
+$(info Makefile:1: Visibility prefix should not start with ../)
+endif
+
+test:
+ @: