@@ -325,6 +325,52 @@ void VariableLookupAnalysis::dfs(const ExprWith &With,
325325 }
326326}
327327
328+ void VariableLookupAnalysis::checkBuiltins (const ExprSelect &Sel) {
329+ if (!Sel.path ())
330+ return ;
331+
332+ if (Sel.expr ().kind () != Node::NK_ExprVar)
333+ return ;
334+
335+ const auto &Builtins = static_cast <const ExprVar &>(Sel.expr ());
336+ if (Builtins.id ().name () != " builtins" )
337+ return ;
338+
339+ const auto &AP = *Sel.path ();
340+
341+ if (AP.names ().size () != 1 )
342+ return ;
343+
344+ AttrName &First = *AP.names ()[0 ];
345+ if (!First.isStatic ())
346+ return ;
347+
348+ const auto &Name = First.staticName ();
349+
350+ switch (lookupGlobalPrimOpInfo (Name)) {
351+ case PrimopLookupResult::Found: {
352+ Diagnostic &D = Diags.emplace_back (Diagnostic::DK_PrimOpRemovablePrefix,
353+ Builtins.range ());
354+ Fix &F =
355+ D.fix (" remove `builtins.` prefix" )
356+ .edit (TextEdit::mkRemoval (Builtins.range ())); // remove `builtins`
357+
358+ if (Sel.dot ()) {
359+ // remove the dot also.
360+ F.edit (TextEdit::mkRemoval (Sel.dot ()->range ()));
361+ }
362+ return ;
363+ }
364+ case PrimopLookupResult::PrefixedFound:
365+ return ;
366+ case PrimopLookupResult::NotFound:
367+ Diagnostic &D = Diags.emplace_back (Diagnostic::DK_PrimOpUnknown,
368+ AP.names ()[0 ]->range ());
369+ D << Name;
370+ return ;
371+ }
372+ }
373+
328374void VariableLookupAnalysis::dfs (const Node &Root,
329375 const std::shared_ptr<EnvNode> &Env) {
330376 Envs.insert ({&Root, Env});
@@ -354,6 +400,12 @@ void VariableLookupAnalysis::dfs(const Node &Root,
354400 dfs (With, Env);
355401 break ;
356402 }
403+ case Node::NK_ExprSelect: {
404+ trivialDispatch (Root, Env);
405+ const auto &Sel = static_cast <const ExprSelect &>(Root);
406+ checkBuiltins (Sel);
407+ break ;
408+ }
357409 default :
358410 trivialDispatch (Root, Env);
359411 }
0 commit comments