summaryrefslogtreecommitdiff
path: root/pkgtools/pkglint/files/mklines.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkgtools/pkglint/files/mklines.go')
-rw-r--r--pkgtools/pkglint/files/mklines.go190
1 files changed, 105 insertions, 85 deletions
diff --git a/pkgtools/pkglint/files/mklines.go b/pkgtools/pkglint/files/mklines.go
index 882fdf91982..fae2f2165f4 100644
--- a/pkgtools/pkglint/files/mklines.go
+++ b/pkgtools/pkglint/files/mklines.go
@@ -4,9 +4,10 @@ import "strings"
// MkLines contains data for the Makefile (or *.mk) that is currently checked.
type MkLines struct {
- mklines []*MkLine
- lines *Lines
- target string // Current make(1) target; only available during checkAll
+ mklines []*MkLine
+ lines *Lines
+ pkg *Package
+
allVars Scope // The variables after loading the complete file
buildDefs map[string]bool // Variables that are registered in BUILD_DEFS, to ensure that all user-defined variables are added to it.
plistVarAdded map[string]*MkLine // Identifiers that are added to PLIST_VARS.
@@ -14,15 +15,28 @@ type MkLines struct {
plistVarSkip bool // True if any of the PLIST_VARS identifiers refers to a variable.
Tools *Tools // Tools defined in file scope.
indentation *Indentation // Indentation depth of preprocessing directives; only available during MkLines.ForEach.
- forVars map[string]bool // The variables currently used in .for loops; only available during MkLines.checkAll.
once Once
- postLine func(mkline *MkLine) // Custom action that is run after checking each line
// TODO: Consider extracting plistVarAdded, plistVarSet, plistVarSkip into an own type.
// TODO: Describe where each of the above fields is valid.
+
+ checkAllData mklinesCheckAll
}
-func NewMkLines(lines *Lines) *MkLines {
+type mklinesCheckAll struct {
+ // Current make(1) target
+ target string
+
+ vars Scope
+
+ // The variables currently used in .for loops
+ forVars map[string]bool
+
+ // Custom action that is run after checking each line
+ postLine func(mkline *MkLine)
+}
+
+func NewMkLines(lines *Lines, pkg *Package) *MkLines {
mklines := make([]*MkLine, lines.Len())
for i, line := range lines.Lines {
mklines[i] = NewMkLineParser().Parse(line)
@@ -34,7 +48,7 @@ func NewMkLines(lines *Lines) *MkLines {
return &MkLines{
mklines,
lines,
- "",
+ pkg,
NewScope(),
make(map[string]bool),
make(map[string]*MkLine),
@@ -42,9 +56,12 @@ func NewMkLines(lines *Lines) *MkLines {
false,
tools,
nil,
- make(map[string]bool),
Once{},
- nil}
+ mklinesCheckAll{
+ target: "",
+ vars: NewScope(),
+ forVars: make(map[string]bool),
+ postLine: nil}}
}
// TODO: Consider defining an interface MkLinesChecker (different name, though, since this one confuses even me)
@@ -81,9 +98,8 @@ func (mklines *MkLines) Check() {
mklines.collectUsedVariables()
mklines.collectVariables()
mklines.collectPlistVars()
- mklines.collectElse()
- if G.Pkg != nil {
- G.Pkg.collectConditionalIncludes(mklines)
+ if mklines.pkg != nil {
+ mklines.pkg.collectConditionalIncludes(mklines)
}
// In the second pass, the actual checks are done.
@@ -138,8 +154,8 @@ func (mklines *MkLines) collectUsedVariables() {
// This controls the "defined but not used" warning.
func (mklines *MkLines) UseVar(mkline *MkLine, varname string, time VucTime) {
mklines.allVars.Use(varname, mkline, time)
- if G.Pkg != nil {
- G.Pkg.vars.Use(varname, mkline, time)
+ if mklines.pkg != nil {
+ mklines.pkg.vars.Use(varname, mkline, time)
}
}
@@ -160,10 +176,10 @@ func (mklines *MkLines) collectDocumentedVariables() {
// The commentLines include the the line containing the variable name,
// leaving 2 of these 3 lines for the actual documentation.
if commentLines >= 3 && relevant {
- for varname, mkline := range scope.used {
+ forEachStringMkLine(scope.used, func(varname string, mkline *MkLine) {
mklines.allVars.Define(varname, mkline)
mklines.allVars.Use(varname, mkline, VucRunTime)
- }
+ })
}
scope = NewScope()
@@ -219,63 +235,67 @@ func (mklines *MkLines) collectVariables() {
}
mklines.ForEach(func(mkline *MkLine) {
- mklines.Tools.ParseToolLine(mklines, mkline, false, true)
+ mklines.collectVariable(mkline)
+ })
+}
- if !mkline.IsVarassignMaybeCommented() {
- return
- }
+func (mklines *MkLines) collectVariable(mkline *MkLine) {
+ mklines.Tools.ParseToolLine(mklines, mkline, false, true)
- mklines.defineVar(G.Pkg, mkline, mkline.Varname())
-
- varcanon := mkline.Varcanon()
- switch varcanon {
- case
- "BUILD_DEFS",
- "PKG_GROUPS_VARS", // see mk/misc/unprivileged.mk
- "PKG_USERS_VARS": // see mk/misc/unprivileged.mk
- for _, varname := range mkline.Fields() {
- mklines.buildDefs[varname] = true
- if trace.Tracing {
- trace.Step1("%q is added to BUILD_DEFS.", varname)
- }
- }
+ if !mkline.IsVarassignMaybeCommented() {
+ return
+ }
- case
- "BUILTIN_FIND_FILES_VAR",
- "BUILTIN_FIND_HEADERS_VAR":
- for _, varname := range mkline.Fields() {
- mklines.allVars.Define(varname, mkline)
+ mklines.defineVar(mkline, mkline.Varname())
+
+ varcanon := mkline.Varcanon()
+ switch varcanon {
+ case
+ "BUILD_DEFS",
+ "PKG_GROUPS_VARS", // see mk/misc/unprivileged.mk
+ "PKG_USERS_VARS": // see mk/misc/unprivileged.mk
+ for _, varname := range mkline.Fields() {
+ mklines.buildDefs[varname] = true
+ if trace.Tracing {
+ trace.Step1("%q is added to BUILD_DEFS.", varname)
}
+ }
- case "PLIST_VARS":
- for _, id := range mkline.ValueFields(resolveVariableRefs(mklines, mkline.Value())) {
- if trace.Tracing {
- trace.Step1("PLIST.%s is added to PLIST_VARS.", id)
- }
+ case
+ "BUILTIN_FIND_FILES_VAR",
+ "BUILTIN_FIND_HEADERS_VAR":
+ for _, varname := range mkline.Fields() {
+ mklines.allVars.Define(varname, mkline)
+ }
- if containsVarRef(id) {
- mklines.UseVar(mkline, "PLIST.*", mkline.Op().Time())
- mklines.plistVarSkip = true
- } else {
- mklines.UseVar(mkline, "PLIST."+id, mkline.Op().Time())
- }
+ case "PLIST_VARS":
+ for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value(), mklines, nil)) {
+ if trace.Tracing {
+ trace.Step1("PLIST.%s is added to PLIST_VARS.", id)
}
- case "SUBST_VARS.*":
- for _, substVar := range mkline.Fields() {
- mklines.UseVar(mkline, varnameCanon(substVar), mkline.Op().Time())
- if trace.Tracing {
- trace.Step1("varuse %s", substVar)
- }
+ if containsVarUse(id) {
+ mklines.UseVar(mkline, "PLIST.*", mkline.Op().Time())
+ mklines.plistVarSkip = true
+ } else {
+ mklines.UseVar(mkline, "PLIST."+id, mkline.Op().Time())
}
+ }
- case "OPSYSVARS":
- for _, opsysVar := range mkline.Fields() {
- mklines.UseVar(mkline, opsysVar+".*", mkline.Op().Time())
- mklines.defineVar(G.Pkg, mkline, opsysVar)
+ case "SUBST_VARS.*":
+ for _, substVar := range mkline.Fields() {
+ mklines.UseVar(mkline, varnameCanon(substVar), mkline.Op().Time())
+ if trace.Tracing {
+ trace.Step1("varuse %s", substVar)
}
}
- })
+
+ case "OPSYSVARS":
+ for _, opsysVar := range mkline.Fields() {
+ mklines.UseVar(mkline, opsysVar+".*", mkline.Op().Time())
+ mklines.defineVar(mkline, opsysVar)
+ }
+ }
}
// ForEach calls the action for each line, until the action returns false.
@@ -322,10 +342,10 @@ func (mklines *MkLines) ForEachEnd(action func(mkline *MkLine) bool, atEnd func(
}
// defineVar marks a variable as defined in both the current package and the current file.
-func (mklines *MkLines) defineVar(pkg *Package, mkline *MkLine, varname string) {
+func (mklines *MkLines) defineVar(mkline *MkLine, varname string) {
mklines.allVars.Define(varname, mkline)
- if pkg != nil {
- pkg.vars.Define(varname, mkline)
+ if mklines.pkg != nil {
+ mklines.pkg.vars.Define(varname, mkline)
}
}
@@ -335,8 +355,8 @@ func (mklines *MkLines) collectPlistVars() {
if mkline.IsVarassign() {
switch mkline.Varcanon() {
case "PLIST_VARS":
- for _, id := range mkline.ValueFields(resolveVariableRefs(mklines, mkline.Value())) {
- if containsVarRef(id) {
+ for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value(), mklines, nil)) {
+ if containsVarUse(id) {
mklines.plistVarSkip = true
} else {
mklines.plistVarAdded[id] = mkline
@@ -344,7 +364,7 @@ func (mklines *MkLines) collectPlistVars() {
}
case "PLIST.*":
id := mkline.Varparam()
- if containsVarRef(id) {
+ if containsVarUse(id) {
mklines.plistVarSkip = true
} else {
mklines.plistVarSet[id] = mkline
@@ -354,13 +374,11 @@ func (mklines *MkLines) collectPlistVars() {
}
}
-func (mklines *MkLines) collectElse() {
- // Make a dry-run over the lines, which sets data.elseLine (in mkline.go) as a side-effect.
- mklines.ForEach(func(mkline *MkLine) {})
- // TODO: Check whether this ForEach is redundant because it is already run somewhere else.
-}
-
func (mklines *MkLines) checkAll() {
+ // checkAll must only be called once, even during tests, since it
+ // doesn't clean up all its effects on mklines.
+ assert(mklines.once.FirstTime("checkAll"))
+
allowedTargets := map[string]bool{
"pre-fetch": true, "do-fetch": true, "post-fetch": true,
"pre-extract": true, "do-extract": true, "post-extract": true,
@@ -376,7 +394,7 @@ func (mklines *MkLines) checkAll() {
mklines.lines.CheckCvsID(0, `#[\t ]+`, "# ")
- substContext := NewSubstContext()
+ substContext := NewSubstContext(mklines.pkg)
var varalign VaralignBlock
vargroupsChecker := NewVargroupsChecker(mklines)
isHacksMk := mklines.lines.BaseName == "hacks.mk"
@@ -397,7 +415,7 @@ func (mklines *MkLines) checkAll() {
// This check is not done by ForEach because ForEach only
// manages the iteration, not the actual checks.
mklines.indentation.CheckFinish(mklines.lines.Filename)
- vargroupsChecker.Finish(mkline)
+ vargroupsChecker.Finish()
})
substContext.Finish(mklines.EOFLine())
@@ -424,37 +442,39 @@ func (mklines *MkLines) checkLine(
switch {
case mkline.IsVarassign():
- mklines.target = ""
+ mklines.checkAllData.target = ""
mkline.Tokenize(mkline.Value(), true) // Just for the side-effect of the warnings.
mklines.checkVarassignPlist(mkline)
+ varname := mkline.Varname()
+ mklines.checkAllData.vars.Define(varname, mkline)
case mkline.IsInclude():
- mklines.target = ""
- if G.Pkg != nil {
- G.Pkg.checkIncludeConditionally(mkline, mklines.indentation)
+ mklines.checkAllData.target = ""
+ if mklines.pkg != nil {
+ mklines.pkg.checkIncludeConditionally(mkline, mklines.indentation)
}
case mkline.IsDirective():
- ck.checkDirective(mklines.forVars, mklines.indentation)
+ ck.checkDirective(mklines.checkAllData.forVars, mklines.indentation)
case mkline.IsDependency():
ck.checkDependencyRule(allowedTargets)
- mklines.target = mkline.Targets()
+ mklines.checkAllData.target = mkline.Targets()
case mkline.IsShellCommand():
mkline.Tokenize(mkline.ShellCommand(), true) // Just for the side-effect of the warnings.
}
- if mklines.postLine != nil {
- mklines.postLine(mkline)
+ if mklines.checkAllData.postLine != nil {
+ mklines.checkAllData.postLine(mkline)
}
}
func (mklines *MkLines) checkVarassignPlist(mkline *MkLine) {
switch mkline.Varcanon() {
case "PLIST_VARS":
- for _, id := range mkline.ValueFields(resolveVariableRefs(mklines, mkline.Value())) {
+ for _, id := range mkline.ValueFields(resolveVariableRefs(mkline.Value(), mklines, nil)) {
if !mklines.plistVarSkip && mklines.plistVarSet[id] == nil {
mkline.Warnf("%q is added to PLIST_VARS, but PLIST.%s is not defined in this file.", id, id)
}
@@ -611,7 +631,7 @@ func (mklines *MkLines) ExpandLoopVar(varname string) []string {
}
// TODO: If needed, add support for multi-variable .for loops.
- resolved := resolveVariableRefs(mklines, mkline.Args())
+ resolved := resolveVariableRefs(mkline.Args(), mklines, nil)
words := mkline.ValueFields(resolved)
if len(words) >= 3 && words[0] == varname && words[1] == "in" {
return words[2:]