diff options
-rw-r--r-- | src/expr.cc | 2 | ||||
-rw-r--r-- | src/find.cc | 2 | ||||
-rw-r--r-- | src/func.cc | 57 | ||||
-rw-r--r-- | src/strutil.cc | 5 | ||||
-rw-r--r-- | src/strutil.h | 5 | ||||
-rw-r--r-- | src/symtab.cc | 2 | ||||
-rw-r--r-- | src/var.cc | 35 | ||||
-rw-r--r-- | src/var.h | 9 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_conflict.mk | 16 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_implicit_define.mk | 6 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_invalid_file_four.mk | 16 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_invalid_file_one.mk | 23 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_invalid_file_two.mk | 16 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_invalid_prefix_four.mk | 8 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_invalid_prefix_one.mk | 8 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_invalid_prefix_three.mk | 9 | ||||
-rw-r--r-- | testcase/var_visibility_prefix_invalid_prefix_two.mk | 8 |
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" @@ -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(); @@ -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: + @: |