Better messaging for 4281
[hiphop-php.git] / hphp / compiler / option.cpp
blob6e07708ee618cb1842c72148286d04e4cfc9beb6
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/compiler/option.h"
19 #include <map>
20 #include <set>
21 #include <string>
22 #include <vector>
24 #include "hphp/compiler/analysis/analysis_result.h"
25 #include "hphp/compiler/analysis/class_scope.h"
26 #include "hphp/compiler/analysis/file_scope.h"
28 #include "hphp/parser/scanner.h"
30 #include "hphp/runtime/base/config.h"
31 #include "hphp/runtime/base/ini-setting.h"
32 #include "hphp/runtime/base/preg.h"
33 #include "hphp/runtime/base/variable-unserializer.h"
35 #include "hphp/util/hdf.h"
36 #include "hphp/util/logger.h"
37 #include "hphp/util/process.h"
38 #include "hphp/util/text-util.h"
40 #include "hphp/hhbbc/hhbbc.h"
42 namespace HPHP {
43 ///////////////////////////////////////////////////////////////////////////////
45 std::string Option::RootDirectory;
46 std::set<std::string> Option::PackageDirectories;
47 std::set<std::string> Option::PackageFiles;
48 std::set<std::string> Option::PackageExcludeDirs;
49 std::set<std::string> Option::PackageExcludeFiles;
50 std::set<std::string> Option::PackageExcludePatterns;
51 std::set<std::string> Option::PackageExcludeStaticDirs;
52 std::set<std::string> Option::PackageExcludeStaticFiles;
53 std::set<std::string> Option::PackageExcludeStaticPatterns;
54 bool Option::CachePHPFile = false;
56 std::vector<std::string> Option::ParseOnDemandDirs;
58 std::vector<std::string> Option::IncludeSearchPaths;
60 std::set<std::string> Option::VolatileClasses;
61 std::map<std::string,std::string,stdltistr> Option::AutoloadClassMap;
62 std::map<std::string,std::string,stdltistr> Option::AutoloadFuncMap;
63 std::map<std::string,std::string> Option::AutoloadConstMap;
64 std::string Option::AutoloadRoot;
66 std::vector<std::string> Option::APCProfile;
68 bool Option::GenerateTextHHBC = false;
69 bool Option::GenerateHhasHHBC = false;
70 bool Option::GenerateBinaryHHBC = false;
71 std::string Option::RepoCentralPath;
73 std::string Option::IdPrefix = "$$";
75 std::string Option::LambdaPrefix = "df_";
76 std::string Option::Tab = " ";
78 const char *Option::UserFilePrefix = "php/";
80 bool Option::KeepStatementsWithNoEffect = false;
82 std::string Option::ProgramName;
84 bool Option::ParseTimeOpts = true;
85 bool Option::EnableHipHopExperimentalSyntax = false;
86 bool Option::EnableShortTags = true;
87 bool Option::EnableAspTags = false;
88 int Option::ParserThreadCount = 0;
90 int Option::GetScannerType() {
91 int type = 0;
92 if (EnableShortTags) type |= Scanner::AllowShortTags;
93 if (EnableAspTags) type |= Scanner::AllowAspTags;
94 if (RuntimeOption::EnableXHP) type |= Scanner::AllowXHPSyntax;
95 if (RuntimeOption::EnableHipHopSyntax) type |= Scanner::AllowHipHopSyntax;
96 return type;
99 bool Option::DumpAst = false;
100 bool Option::WholeProgram = true;
101 bool Option::RecordErrors = true;
103 bool Option::AllVolatile = false;
105 ///////////////////////////////////////////////////////////////////////////////
106 // load from HDF file
108 void Option::LoadRootHdf(const IniSetting::Map& ini,
109 const Hdf &roots,
110 const std::string& name,
111 std::map<std::string, std::string> &map) {
112 auto root_map_callback = [&](const IniSetting::Map& ini_rm, const Hdf& hdf_rm,
113 const std::string& /*ini_rm_key*/) {
114 map[Config::GetString(ini_rm, hdf_rm, "root", "", false)] =
115 Config::GetString(ini_rm, hdf_rm, "path", "", false);
117 Config::Iterate(root_map_callback, ini, roots, name);
120 void Option::Load(const IniSetting::Map& ini, Hdf &config) {
121 LoadRootHdf(ini, config, "IncludeRoots", RuntimeOption::IncludeRoots);
122 LoadRootHdf(ini, config, "AutoloadRoots", RuntimeOption::AutoloadRoots);
124 Config::Bind(PackageFiles, ini, config, "PackageFiles", PackageFiles);
125 Config::Bind(IncludeSearchPaths, ini, config, "IncludeSearchPaths");
126 Config::Bind(PackageDirectories, ini, config, "PackageDirectories");
127 Config::Bind(PackageExcludeDirs, ini, config, "PackageExcludeDirs");
128 Config::Bind(PackageExcludeFiles, ini, config, "PackageExcludeFiles");
129 Config::Bind(PackageExcludePatterns, ini, config, "PackageExcludePatterns");
130 Config::Bind(PackageExcludeStaticDirs, ini,
131 config, "PackageExcludeStaticDirs");
132 Config::Bind(PackageExcludeStaticFiles, ini,
133 config, "PackageExcludeStaticFiles");
134 Config::Bind(PackageExcludeStaticFiles, ini,
135 config, "PackageExcludeStaticPatterns");
136 Config::Bind(CachePHPFile, ini, config, "CachePHPFile");
138 Config::Bind(RuntimeOption::EvalDisableReturnByReference,
139 ini, config, "DisableReturnByReference",
140 RuntimeOption::EvalDisableReturnByReference);
142 Config::Bind(ParseOnDemandDirs, ini, config, "ParseOnDemandDirs");
144 Config::Bind(IdPrefix, ini, config, "CodeGeneration.IdPrefix", IdPrefix);
145 Config::Bind(LambdaPrefix, ini, config,
146 "CodeGeneration.LambdaPrefix", LambdaPrefix);
148 Config::Bind(RuntimeOption::DynamicInvokeFunctions,
149 ini, config, "DynamicInvokeFunctions",
150 RuntimeOption::DynamicInvokeFunctions);
151 Config::Bind(VolatileClasses, ini, config, "VolatileClasses");
153 Config::GetBool(ini, config, "FlattenTraits");
155 for (auto& str : Config::GetStrVector(ini, config, "ConstantFunctions")) {
156 std::string func;
157 std::string value;
158 if (folly::split('|', str, func, value)) {
159 VariableUnserializer uns{
160 value.data(), value.size(),
161 VariableUnserializer::Type::Internal,
162 false, empty_array()
164 try {
165 auto v = uns.unserialize();
166 v.setEvalScalar();
167 RuntimeOption::ConstantFunctions[func] = *v.toCell();
168 continue;
169 } catch (const Exception& e) {
170 // fall through and log
173 Logger::FError("Invalid ConstantFunction: '{}'\n", str);
177 // Repo
179 // Repo Central
180 Config::Bind(RepoCentralPath, ini, config, "Repo.Central.Path");
182 Config::Bind(RuntimeOption::RepoDebugInfo,
183 ini, config, "Repo.DebugInfo",
184 RuntimeOption::RepoDebugInfo);
188 // AutoloadMap
189 Config::Bind(AutoloadClassMap, ini, config, "AutoloadMap.class");
190 Config::Bind(AutoloadFuncMap, ini, config, "AutoloadMap.function");
191 Config::Bind(AutoloadConstMap, ini, config, "AutoloadMap.constant");
192 Config::Bind(AutoloadRoot, ini, config, "AutoloadMap.root");
195 Config::Bind(RuntimeOption::EvalHardTypeHints, ini, config,
196 "HardTypeHints", RuntimeOption::EvalHardTypeHints);
198 static bool HardReturnTypeHints;
199 Config::Bind(HardReturnTypeHints, ini, config, "HardReturnTypeHints", true);
201 Config::Bind(RuntimeOption::EvalCheckPropTypeHints, ini, config,
202 "CheckPropTypeHints", RuntimeOption::EvalCheckPropTypeHints);
204 // This option takes precedence over RuntimeOption. We test to see if the
205 // option has been set (by the user) or not.
206 auto is_set = [&](const std::string& key) {
207 auto a = Config::GetBool(ini, config, key, true);
208 auto b = Config::GetBool(ini, config, key, false);
209 return a == b;
212 if (!is_set("CheckReturnTypeHints") || is_set("HardReturnTypeHints")) {
213 // Note that the actual value does not matter, since HHBBC only cares about
214 // whether the value is 3 or not.
215 RuntimeOption::EvalCheckReturnTypeHints = HardReturnTypeHints ? 3 : 2;
218 Config::Bind(HHBBC::options.HardConstProp, ini, config,
219 "HardConstProp", HHBBC::options.HardConstProp);
220 Config::Bind(HHBBC::options.ElideAutoloadInvokes, ini, config,
221 "ElideAutoloadInvokes", HHBBC::options.ElideAutoloadInvokes);
223 Config::Bind(APCProfile, ini, config, "APCProfile");
225 Config::Bind(RuntimeOption::EvalThisTypeHintLevel, ini, config,
226 "ThisTypeHintLevel", RuntimeOption::EvalThisTypeHintLevel);
228 Config::Bind(RuntimeOption::EnableHipHopSyntax,
229 ini, config, "EnableHipHopSyntax",
230 RuntimeOption::EnableHipHopSyntax);
231 Config::Bind(RuntimeOption::EvalPromoteEmptyObject,
232 ini, config, "PromoteEmptyObject",
233 RuntimeOption::EvalPromoteEmptyObject);
234 Config::Bind(RuntimeOption::EvalJitEnableRenameFunction,
235 ini, config, "JitEnableRenameFunction",
236 RuntimeOption::EvalJitEnableRenameFunction);
237 Config::Bind(EnableHipHopExperimentalSyntax, ini,
238 config, "EnableHipHopExperimentalSyntax");
239 Config::Bind(EnableShortTags, ini, config, "EnableShortTags", true);
241 #define BIND_HAC_OPTION(Name, Def) \
242 Config::Bind(RuntimeOption::EvalHackArrCompat##Name, \
243 ini, config, "HackArrCompat" #Name, \
244 RuntimeOption::EvalHackArrCompat##Def);
246 #define BIND_HAC_OPTION_SELF(Name) BIND_HAC_OPTION(Name, Name)
248 BIND_HAC_OPTION_SELF(Notices)
249 BIND_HAC_OPTION(CheckIntishCast, Notices)
250 BIND_HAC_OPTION(CheckRefBind, Notices)
251 BIND_HAC_OPTION(CheckFalseyPromote, Notices)
252 BIND_HAC_OPTION(CheckCompare, Notices)
253 BIND_HAC_OPTION(CheckArrayKeyCast, Notices)
254 BIND_HAC_OPTION(CheckArrayPlus, Notices)
255 BIND_HAC_OPTION_SELF(IsArrayNotices)
256 BIND_HAC_OPTION_SELF(PromoteNotices)
257 BIND_HAC_OPTION_SELF(TypeHintNotices)
258 BIND_HAC_OPTION_SELF(DVCmpNotices)
259 BIND_HAC_OPTION_SELF(SerializeNotices)
260 BIND_HAC_OPTION_SELF(CompactSerializeNotices)
262 #undef BIND_HAC_OPTION_SELF
263 #undef BIND_HAC_OPTION
265 Config::Bind(RuntimeOption::EvalHackArrDVArrs,
266 ini, config, "HackArrDVArrs",
267 RuntimeOption::EvalHackArrDVArrs);
269 Config::Bind(RuntimeOption::EvalForbidDynamicCalls,
270 ini, config, "ForbidDynamicCalls",
271 RuntimeOption::EvalForbidDynamicCalls);
272 Config::Bind(RuntimeOption::EvalNoticeOnBuiltinDynamicCalls,
273 ini, config, "NoticeOnBuiltinDynamicCalls",
274 RuntimeOption::EvalNoticeOnBuiltinDynamicCalls);
275 Config::Bind(RuntimeOption::EvalAllowObjectDestructors,
276 ini, config, "AllowObjectDestructors",
277 RuntimeOption::EvalAllowObjectDestructors);
278 Config::Bind(RuntimeOption::EvalAbortBuildOnVerifyError,
279 ini, config, "AbortBuildOnVerifyError",
280 RuntimeOption::EvalAbortBuildOnVerifyError);
283 // Hack
284 Config::Bind(RuntimeOption::IntsOverflowToInts, ini, config,
285 "Hack.Lang.IntsOverflowToInts",
286 RuntimeOption::IntsOverflowToInts);
287 Config::Bind(RuntimeOption::StrictArrayFillKeys, ini, config,
288 "Hack.Lang.StrictArrayFillKeys",
289 RuntimeOption::StrictArrayFillKeys);
290 Config::Bind(RuntimeOption::DisallowDynamicVarEnvFuncs, ini, config,
291 "Hack.Lang.DisallowDynamicVarEnvFuncs",
292 RuntimeOption::DisallowDynamicVarEnvFuncs);
295 Config::Bind(EnableAspTags, ini, config, "EnableAspTags");
297 Config::Bind(RuntimeOption::EnableXHP, ini, config, "EnableXHP",
298 RuntimeOption::EnableXHP);
300 if (RuntimeOption::EnableHipHopSyntax) {
301 // If EnableHipHopSyntax is true, it forces EnableXHP to true
302 // regardless of how it was set in the config
303 RuntimeOption::EnableXHP = true;
306 Config::Bind(ParserThreadCount, ini, config, "ParserThreadCount", 0);
307 if (ParserThreadCount <= 0) {
308 ParserThreadCount = Process::GetCPUCount();
311 // Just to silence warnings until we remove them from various config files
312 (void)Config::GetByte(ini, config, "EnableEval", 0);
313 (void)Config::GetBool(ini, config, "AllDynamic", true);
315 Config::Bind(AllVolatile, ini, config, "AllVolatile");
317 Config::Bind(RuntimeOption::EvalGenerateDocComments, ini, config,
318 "GenerateDocComments", RuntimeOption::EvalGenerateDocComments);
319 Config::Bind(DumpAst, ini, config, "DumpAst", false);
320 Config::Bind(WholeProgram, ini, config, "WholeProgram", true);
321 Config::Bind(RuntimeOption::EvalUseHHBBC, ini, config, "UseHHBBC",
322 RuntimeOption::EvalUseHHBBC);
324 // Temporary, during file-cache migration.
325 Config::Bind(FileCache::UseNewCache, ini, config, "UseNewCache", false);
328 void Option::Load() {
331 ///////////////////////////////////////////////////////////////////////////////
333 std::string Option::MangleFilename(const std::string &name, bool id) {
334 std::string ret = UserFilePrefix;
335 ret += name;
337 if (id) {
338 replaceAll(ret, "/", "$");
339 replaceAll(ret, "-", "_");
340 replaceAll(ret, ".", "_");
342 return ret;
345 bool Option::IsFileExcluded(const std::string &file,
346 const std::set<std::string> &patterns) {
347 String sfile(file.c_str(), file.size(), CopyString);
348 for (auto const& pattern : patterns) {
349 Variant matches;
350 Variant ret = preg_match(String(pattern.c_str(), pattern.size(),
351 CopyString), sfile, &matches);
352 if (ret.toInt64() > 0) {
353 return true;
356 return false;
359 void Option::FilterFiles(std::vector<std::string> &files,
360 const std::set<std::string> &patterns) {
361 auto const it = std::remove_if(
362 files.begin(),
363 files.end(),
364 [&](const std::string& file) { return IsFileExcluded(file, patterns); });
365 files.erase(it, files.end());
368 //////////////////////////////////////////////////////////////////////