[BACK]Return to redundantscope_test.go CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / pkgsrc / pkgtools / pkglint / files

Annotation of pkgsrc/pkgtools/pkglint/files/redundantscope_test.go, Revision 1.10

1.1       rillig      1: package pkglint
                      2:
                      3: import "gopkg.in/check.v1"
                      4:
                      5: // In a single file, five variables get a default value and are later overridden
                      6: // with the same value using the five different assignments operators.
                      7: func (s *Suite) Test_RedundantScope__single_file_default(c *check.C) {
                      8:        t := s.Init(c)
                      9:
                     10:        mklines := t.NewMkLines("file.mk",
1.2       rillig     11:                "VAR.def?=       value",
                     12:                "VAR.asg?=       value",
                     13:                "VAR.app?=       value",
                     14:                "VAR.evl?=       value",
                     15:                "VAR.shl?=       value",
1.1       rillig     16:                "",
1.2       rillig     17:                "VAR.def?=       value",
                     18:                "VAR.asg=        value",
                     19:                "VAR.app+=       value",
                     20:                "VAR.evl:=       value",
                     21:                "VAR.shl!=       value")
1.1       rillig     22:
                     23:        NewRedundantScope().Check(mklines)
                     24:
                     25:        t.CheckOutputLines(
1.2       rillig     26:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                     27:                "NOTE: file.mk:8: Definition of VAR.asg is redundant because of line 2.",
1.10    ! rillig     28:                "NOTE: file.mk:10: Definition of VAR.evl is redundant because of line 4.")
1.2       rillig     29:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig     30: }
                     31:
                     32: // In a single file, five variables get assigned are value and are later overridden
                     33: // with the same value using the five different assignments operators.
                     34: func (s *Suite) Test_RedundantScope__single_file_assign(c *check.C) {
                     35:        t := s.Init(c)
                     36:
                     37:        mklines := t.NewMkLines("file.mk",
1.2       rillig     38:                "VAR.def=        value",
                     39:                "VAR.asg=        value",
                     40:                "VAR.app=        value",
                     41:                "VAR.evl=        value",
                     42:                "VAR.shl=        value",
1.1       rillig     43:                "",
1.2       rillig     44:                "VAR.def?=       value",
                     45:                "VAR.asg=        value",
                     46:                "VAR.app+=       value",
                     47:                "VAR.evl:=       value",
                     48:                "VAR.shl!=       value")
1.1       rillig     49:
                     50:        NewRedundantScope().Check(mklines)
                     51:
                     52:        t.CheckOutputLines(
1.2       rillig     53:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                     54:                "NOTE: file.mk:8: Definition of VAR.asg is redundant because of line 2.",
1.10    ! rillig     55:                "NOTE: file.mk:10: Definition of VAR.evl is redundant because of line 4.")
1.2       rillig     56:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig     57: }
                     58:
                     59: // In a single file, five variables get appended a value and are later overridden
                     60: // with the same value using the five different assignments operators.
                     61: func (s *Suite) Test_RedundantScope__single_file_append(c *check.C) {
                     62:        t := s.Init(c)
                     63:
                     64:        mklines := t.NewMkLines("file.mk",
1.2       rillig     65:                "VAR.def+=       value",
                     66:                "VAR.asg+=       value",
                     67:                "VAR.app+=       value",
                     68:                "VAR.evl+=       value",
                     69:                "VAR.shl+=       value",
1.1       rillig     70:                "",
1.2       rillig     71:                "VAR.def?=       value",
                     72:                "VAR.asg=        value",
                     73:                "VAR.app+=       value",
                     74:                "VAR.evl:=       value",
                     75:                "VAR.shl!=       value")
1.1       rillig     76:
                     77:        NewRedundantScope().Check(mklines)
                     78:
                     79:        t.CheckOutputLines(
1.2       rillig     80:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                     81:                "WARN: file.mk:2: Variable VAR.asg is overwritten in line 8.",
                     82:                "WARN: file.mk:4: Variable VAR.evl is overwritten in line 10.")
                     83:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig     84: }
                     85:
                     86: // In a single file, five variables get assigned a value using the := operator,
                     87: // which in this simple case is equivalent to the = operator. The variables are
                     88: // later overridden with the same value using the five different assignments operators.
                     89: func (s *Suite) Test_RedundantScope__single_file_eval(c *check.C) {
                     90:        t := s.Init(c)
                     91:
                     92:        mklines := t.NewMkLines("file.mk",
1.2       rillig     93:                "VAR.def:=       value",
                     94:                "VAR.asg:=       value",
                     95:                "VAR.app:=       value",
                     96:                "VAR.evl:=       value",
                     97:                "VAR.shl:=       value",
1.1       rillig     98:                "",
1.2       rillig     99:                "VAR.def?=       value",
                    100:                "VAR.asg=        value",
                    101:                "VAR.app+=       value",
                    102:                "VAR.evl:=       value",
                    103:                "VAR.shl!=       value")
1.1       rillig    104:
                    105:        NewRedundantScope().Check(mklines)
                    106:
                    107:        t.CheckOutputLines(
1.2       rillig    108:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                    109:                "NOTE: file.mk:8: Definition of VAR.asg is redundant because of line 2.",
1.10    ! rillig    110:                "NOTE: file.mk:10: Definition of VAR.evl is redundant because of line 4.")
1.2       rillig    111:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig    112: }
                    113:
                    114: // In a single file, five variables get assigned a value using the != operator,
                    115: // which runs a shell command. As of March 2019 pkglint doesn't try to evaluate
                    116: // the shell commands, therefore the variable values are unknown. The variables
                    117: // are later overridden using the five different assignments operators.
                    118: func (s *Suite) Test_RedundantScope__single_file_shell(c *check.C) {
                    119:        t := s.Init(c)
                    120:
                    121:        mklines := t.NewMkLines("file.mk",
1.2       rillig    122:                "VAR.def!=       value",
                    123:                "VAR.asg!=       value",
                    124:                "VAR.app!=       value",
                    125:                "VAR.evl!=       value",
                    126:                "VAR.shl!=       value",
1.1       rillig    127:                "",
1.2       rillig    128:                "VAR.def?=       value",
                    129:                "VAR.asg=        value",
                    130:                "VAR.app+=       value",
                    131:                "VAR.evl:=       value",
                    132:                "VAR.shl!=       value")
1.1       rillig    133:
                    134:        NewRedundantScope().Check(mklines)
                    135:
                    136:        t.CheckOutputLines(
1.2       rillig    137:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                    138:                "WARN: file.mk:2: Variable VAR.asg is overwritten in line 8.",
                    139:                "WARN: file.mk:4: Variable VAR.evl is overwritten in line 10.")
                    140:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig    141: }
                    142:
                    143: // In a single file, five variables get a default value and are later overridden
                    144: // with the same value using the five different assignments operators.
                    145: func (s *Suite) Test_RedundantScope__single_file_default_ref(c *check.C) {
                    146:        t := s.Init(c)
                    147:
                    148:        mklines := t.NewMkLines("file.mk",
1.2       rillig    149:                "VAR.def?=       ${OTHER}",
                    150:                "VAR.asg?=       ${OTHER}",
                    151:                "VAR.app?=       ${OTHER}",
                    152:                "VAR.evl?=       ${OTHER}",
                    153:                "VAR.shl?=       ${OTHER}",
1.1       rillig    154:                "",
1.2       rillig    155:                "VAR.def?=       ${OTHER}",
                    156:                "VAR.asg=        ${OTHER}",
                    157:                "VAR.app+=       ${OTHER}",
                    158:                "VAR.evl:=       ${OTHER}",
                    159:                "VAR.shl!=       ${OTHER}")
1.1       rillig    160:
                    161:        NewRedundantScope().Check(mklines)
                    162:
                    163:        t.CheckOutputLines(
1.2       rillig    164:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                    165:                "NOTE: file.mk:8: Definition of VAR.asg is redundant because of line 2.")
                    166:        // TODO: "VAR.evl: is overwritten later",
                    167:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig    168: }
                    169:
                    170: // In a single file, five variables get assigned are value and are later overridden
                    171: // with the same value using the five different assignments operators.
                    172: func (s *Suite) Test_RedundantScope__single_file_assign_ref(c *check.C) {
                    173:        t := s.Init(c)
                    174:
                    175:        mklines := t.NewMkLines("file.mk",
1.2       rillig    176:                "VAR.def=        ${OTHER}",
                    177:                "VAR.asg=        ${OTHER}",
                    178:                "VAR.app=        ${OTHER}",
                    179:                "VAR.evl=        ${OTHER}",
                    180:                "VAR.shl=        ${OTHER}",
1.1       rillig    181:                "",
1.2       rillig    182:                "VAR.def?=       ${OTHER}",
                    183:                "VAR.asg=        ${OTHER}",
                    184:                "VAR.app+=       ${OTHER}",
                    185:                "VAR.evl:=       ${OTHER}",
                    186:                "VAR.shl!=       ${OTHER}")
1.1       rillig    187:
                    188:        NewRedundantScope().Check(mklines)
                    189:
                    190:        t.CheckOutputLines(
1.2       rillig    191:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                    192:                "NOTE: file.mk:8: Definition of VAR.asg is redundant because of line 2.")
                    193:        // TODO: "VAR.evl: is overwritten later",
                    194:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig    195: }
                    196:
                    197: // In a single file, five variables get appended a value and are later overridden
                    198: // with the same value using the five different assignments operators.
                    199: func (s *Suite) Test_RedundantScope__single_file_append_ref(c *check.C) {
                    200:        t := s.Init(c)
                    201:
                    202:        mklines := t.NewMkLines("file.mk",
1.2       rillig    203:                "VAR.def+=       ${OTHER}",
                    204:                "VAR.asg+=       ${OTHER}",
                    205:                "VAR.app+=       ${OTHER}",
                    206:                "VAR.evl+=       ${OTHER}",
                    207:                "VAR.shl+=       ${OTHER}",
1.1       rillig    208:                "",
1.2       rillig    209:                "VAR.def?=       ${OTHER}",
                    210:                "VAR.asg=        ${OTHER}",
                    211:                "VAR.app+=       ${OTHER}",
                    212:                "VAR.evl:=       ${OTHER}",
                    213:                "VAR.shl!=       ${OTHER}")
1.1       rillig    214:
                    215:        NewRedundantScope().Check(mklines)
                    216:
                    217:        t.CheckOutputLines(
1.2       rillig    218:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                    219:                "WARN: file.mk:2: Variable VAR.asg is overwritten in line 8.")
                    220:        // TODO: "VAR.evl: is overwritten later",
                    221:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig    222: }
                    223:
                    224: // In a single file, five variables get assigned a value using the := operator,
                    225: // which in this simple case is equivalent to the = operator. The variables are
                    226: // later overridden with the same value using the five different assignments operators.
                    227: func (s *Suite) Test_RedundantScope__single_file_eval_ref(c *check.C) {
                    228:        t := s.Init(c)
                    229:
                    230:        mklines := t.NewMkLines("file.mk",
1.2       rillig    231:                "VAR.def:=       ${OTHER}",
                    232:                "VAR.asg:=       ${OTHER}",
                    233:                "VAR.app:=       ${OTHER}",
                    234:                "VAR.evl:=       ${OTHER}",
                    235:                "VAR.shl:=       ${OTHER}",
1.1       rillig    236:                "",
1.2       rillig    237:                "VAR.def?=       ${OTHER}",
                    238:                "VAR.asg=        ${OTHER}",
                    239:                "VAR.app+=       ${OTHER}",
                    240:                "VAR.evl:=       ${OTHER}",
                    241:                "VAR.shl!=       ${OTHER}")
1.1       rillig    242:
                    243:        NewRedundantScope().Check(mklines)
                    244:
                    245:        t.CheckOutputLines(
1.2       rillig    246:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                    247:                "NOTE: file.mk:8: Definition of VAR.asg is redundant because of line 2.")
                    248:        // TODO: "VAR.evl: is overwritten later",
                    249:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig    250: }
                    251:
                    252: // In a single file, five variables get assigned a value using the != operator,
                    253: // which runs a shell command. As of March 2019 pkglint doesn't try to evaluate
                    254: // the shell commands, therefore the variable values are unknown. The variables
                    255: // are later overridden using the five different assignments operators.
                    256: func (s *Suite) Test_RedundantScope__single_file_shell_ref(c *check.C) {
                    257:        t := s.Init(c)
                    258:
                    259:        mklines := t.NewMkLines("file.mk",
1.2       rillig    260:                "VAR.def!=       ${OTHER}",
                    261:                "VAR.asg!=       ${OTHER}",
                    262:                "VAR.app!=       ${OTHER}",
                    263:                "VAR.evl!=       ${OTHER}",
                    264:                "VAR.shl!=       ${OTHER}",
1.1       rillig    265:                "",
1.2       rillig    266:                "VAR.def?=       ${OTHER}",
                    267:                "VAR.asg=        ${OTHER}",
                    268:                "VAR.app+=       ${OTHER}",
                    269:                "VAR.evl:=       ${OTHER}",
                    270:                "VAR.shl!=       ${OTHER}")
1.1       rillig    271:
                    272:        NewRedundantScope().Check(mklines)
                    273:
                    274:        t.CheckOutputLines(
1.2       rillig    275:                "NOTE: file.mk:7: Default assignment of VAR.def has no effect because of line 1.",
                    276:                "WARN: file.mk:2: Variable VAR.asg is overwritten in line 8.")
                    277:        // TODO: "VAR.evl: is overwritten later",
                    278:        // TODO: "VAR.shl: is overwritten later"
1.1       rillig    279: }
                    280:
                    281: func (s *Suite) Test_RedundantScope__after_including_same_value(c *check.C) {
                    282:        t := s.Init(c)
                    283:
1.2       rillig    284:        // including.mk:1:  include "included.mk"
                    285:        //   included.mk:1:   VAR.x.y op1 ${OTHER}
                    286:        // including.mk:2:  VAR.x.y op2 ${OTHER}
                    287:        //
                    288:        test := func(includedOp, includingOp string, diagnostics ...string) {
                    289:                opName := [...]string{"asg", "shl", "evl", "app", "def"}
                    290:                varname := sprintf("VAR.%s.%s",
                    291:                        opName[NewMkOperator(includedOp)],
                    292:                        opName[NewMkOperator(includingOp)])
                    293:
                    294:                include, get := t.SetUpHierarchy()
                    295:                include("including.mk",
                    296:                        include("included.mk",
                    297:                                sprintf("%s%s ${OTHER}", varname, includedOp)),
                    298:                        sprintf("%s%s ${OTHER}", varname, includingOp))
                    299:
                    300:                NewRedundantScope().Check(get("including.mk"))
                    301:
                    302:                t.CheckOutput(diagnostics)
                    303:        }
                    304:
                    305:        // As of March 2019, the != operator is ignored for the redundancy check.
                    306:        // TODO: Add the != operator.
                    307:
                    308:        test("?=", "?=",
                    309:                "NOTE: including.mk:2: Default assignment of VAR.def.def has no effect because of included.mk:1.")
                    310:
                    311:        test("?=", "=",
                    312:                "NOTE: including.mk:2: Definition of VAR.def.asg is redundant because of included.mk:1.")
                    313:
                    314:        // VAR.def.app defines a default value and then appends to it. This is a common pattern.
                    315:        // Appending the same value feels redundant but probably doesn't happen in practice.
                    316:        // If it does, there should be a note for it.
                    317:        test("?=", "+=")
                    318:
                    319:        // VAR.def.evl introduces a subtle difference since := evaluates the variable immediately.
                    320:        // Therefore the assignment is not redundant.
                    321:        test("?=", ":=")
                    322:
                    323:        test("=", "?=",
                    324:                "NOTE: including.mk:2: Default assignment of VAR.asg.def has no effect because of included.mk:1.")
                    325:
                    326:        test("=", "=",
                    327:                "NOTE: including.mk:2: Definition of VAR.asg.asg is redundant because of included.mk:1.")
                    328:
                    329:        // VAR.asg.app defines a variable and later appends to it. This is a common pattern.
                    330:        // Appending the same value feels redundant but probably doesn't happen in practice.
                    331:        // If it does, there should be a note for it.
                    332:        test("=", "+=")
                    333:
                    334:        // VAR.asg.evl evaluates the variable immediately and is thus not redundant.
                    335:        test("=", ":=")
                    336:
                    337:        test("+=", "?=",
                    338:                "NOTE: including.mk:2: Default assignment of VAR.app.def has no effect because of included.mk:1.")
                    339:
                    340:        // VAR.app.asg first appends and then overwrites. This might be a mistake.
                    341:        // TODO: Find out whether this case happens in actual pkgsrc and if it's accidental.
                    342:        // VAR.app.app first appends and then appends one more. This is a common pattern.
                    343:        test("+=", "=")
                    344:
                    345:        test("+=", "+=")
                    346:
                    347:        test("+=", ":=")
                    348:
                    349:        test(":=", "?=",
                    350:                "NOTE: including.mk:2: Default assignment of VAR.evl.def has no effect because of included.mk:1.")
                    351:
                    352:        test(":=", "=",
                    353:                "NOTE: including.mk:2: Definition of VAR.evl.asg is redundant because of included.mk:1.")
1.1       rillig    354:
1.2       rillig    355:        test(":=", "+=")
1.1       rillig    356:
1.2       rillig    357:        test(":=", ":=")
1.1       rillig    358: }
                    359:
                    360: func (s *Suite) Test_RedundantScope__after_including_different_value(c *check.C) {
                    361:        t := s.Init(c)
                    362:
                    363:        // Only test the ?=, = and += operators since the others are ignored,
                    364:        // as of March 2019.
                    365:        include, get := t.SetUpHierarchy()
                    366:        include("including.mk",
                    367:                include("included.mk",
1.2       rillig    368:                        "VAR.def.def?=   ${VALUE}",
                    369:                        "VAR.def.asg?=   ${VALUE}",
                    370:                        "VAR.def.app?=   ${VALUE}",
                    371:                        "VAR.asg.def=    ${VALUE}",
                    372:                        "VAR.asg.asg=    ${VALUE}",
                    373:                        "VAR.asg.app=    ${VALUE}",
                    374:                        "VAR.app.def+=   ${VALUE}",
                    375:                        "VAR.app.asg+=   ${VALUE}",
                    376:                        "VAR.app.app+=   ${VALUE}"),
                    377:                "VAR.def.def?=   ${OTHER}",
                    378:                "VAR.def.asg=    ${OTHER}",
                    379:                "VAR.def.app+=   ${OTHER}",
                    380:                "VAR.asg.def?=   ${OTHER}",
                    381:                "VAR.asg.asg=    ${OTHER}",
                    382:                "VAR.asg.app+=   ${OTHER}",
                    383:                "VAR.app.def?=   ${OTHER}",
                    384:                "VAR.app.asg=    ${OTHER}",
                    385:                "VAR.app.app+=   ${OTHER}")
1.1       rillig    386:        mklines := get("including.mk")
                    387:
                    388:        NewRedundantScope().Check(mklines)
                    389:
                    390:        t.CheckOutputLines(
                    391:                "NOTE: including.mk:2: Default assignment of VAR.def.def has no effect because of included.mk:1.",
                    392:                "NOTE: including.mk:5: Default assignment of VAR.asg.def has no effect because of included.mk:4.",
                    393:                "NOTE: including.mk:8: Default assignment of VAR.app.def has no effect because of included.mk:7.")
                    394: }
                    395:
                    396: func (s *Suite) Test_RedundantScope__before_including_same_value(c *check.C) {
                    397:        t := s.Init(c)
                    398:
                    399:        // Only test the ?=, = and += operators since the others are ignored,
                    400:        // as of March 2019.
                    401:        include, get := t.SetUpHierarchy()
                    402:        include("including.mk",
1.2       rillig    403:                "VAR.def.def?=   ${OTHER}",
                    404:                "VAR.def.asg?=   ${OTHER}",
                    405:                "VAR.def.app?=   ${OTHER}",
                    406:                "VAR.asg.def=    ${OTHER}",
                    407:                "VAR.asg.asg=    ${OTHER}",
                    408:                "VAR.asg.app=    ${OTHER}",
                    409:                "VAR.app.def+=   ${OTHER}",
                    410:                "VAR.app.asg+=   ${OTHER}",
                    411:                "VAR.app.app+=   ${OTHER}",
1.1       rillig    412:                include("included.mk",
1.2       rillig    413:                        "VAR.def.def?=   ${OTHER}",
                    414:                        "VAR.def.asg=    ${OTHER}",
                    415:                        "VAR.def.app+=   ${OTHER}",
                    416:                        "VAR.asg.def?=   ${OTHER}",
                    417:                        "VAR.asg.asg=    ${OTHER}",
                    418:                        "VAR.asg.app+=   ${OTHER}",
                    419:                        "VAR.app.def?=   ${OTHER}",
                    420:                        "VAR.app.asg=    ${OTHER}",
                    421:                        "VAR.app.app+=   ${OTHER}"))
1.1       rillig    422:        mklines := get("including.mk")
                    423:
                    424:        NewRedundantScope().Check(mklines)
                    425:
                    426:        t.CheckOutputLines(
                    427:                "NOTE: including.mk:1: Default assignment of VAR.def.def has no effect because of included.mk:1.",
                    428:                "NOTE: including.mk:2: Default assignment of VAR.def.asg has no effect because of included.mk:2.",
                    429:                "NOTE: including.mk:4: Definition of VAR.asg.def is redundant because of included.mk:4.",
                    430:                "NOTE: including.mk:5: Definition of VAR.asg.asg is redundant because of included.mk:5.",
                    431:                "WARN: including.mk:8: Variable VAR.app.asg is overwritten in included.mk:8.")
                    432: }
                    433:
                    434: func (s *Suite) Test_RedundantScope__before_including_different_value(c *check.C) {
                    435:        t := s.Init(c)
                    436:
                    437:        // Only test the ?=, = and += operators since the others are ignored,
                    438:        // as of March 2019.
                    439:        include, get := t.SetUpHierarchy()
                    440:        include("including.mk",
1.2       rillig    441:                "VAR.def.def?=   ${VALUE}",
                    442:                "VAR.def.asg?=   ${VALUE}",
                    443:                "VAR.def.app?=   ${VALUE}",
                    444:                "VAR.asg.def=    ${VALUE}",
                    445:                "VAR.asg.asg=    ${VALUE}",
                    446:                "VAR.asg.app=    ${VALUE}",
                    447:                "VAR.app.def+=   ${VALUE}",
                    448:                "VAR.app.asg+=   ${VALUE}",
                    449:                "VAR.app.app+=   ${VALUE}",
1.1       rillig    450:                include("included.mk",
1.2       rillig    451:                        "VAR.def.def?=   ${OTHER}",
                    452:                        "VAR.def.asg=    ${OTHER}",
                    453:                        "VAR.def.app+=   ${OTHER}",
                    454:                        "VAR.asg.def?=   ${OTHER}",
                    455:                        "VAR.asg.asg=    ${OTHER}",
                    456:                        "VAR.asg.app+=   ${OTHER}",
                    457:                        "VAR.app.def?=   ${OTHER}",
                    458:                        "VAR.app.asg=    ${OTHER}",
                    459:                        "VAR.app.app+=   ${OTHER}"))
1.1       rillig    460:        mklines := get("including.mk")
                    461:
                    462:        NewRedundantScope().Check(mklines)
                    463:
                    464:        t.CheckOutputLines(
                    465:                "WARN: including.mk:2: Variable VAR.def.asg is overwritten in included.mk:2.",
                    466:                "WARN: including.mk:5: Variable VAR.asg.asg is overwritten in included.mk:5.",
                    467:                "WARN: including.mk:8: Variable VAR.app.asg is overwritten in included.mk:8.")
                    468: }
                    469:
                    470: func (s *Suite) Test_RedundantScope__independent_same_value(c *check.C) {
                    471:        t := s.Init(c)
                    472:
                    473:        // Only test the ?=, = and += operators since the others are ignored,
                    474:        // as of March 2019.
                    475:        include, get := t.SetUpHierarchy()
                    476:        include("including.mk",
                    477:                include("included1.mk",
1.2       rillig    478:                        "VAR.def.def?=   ${OTHER}",
                    479:                        "VAR.def.asg?=   ${OTHER}",
                    480:                        "VAR.def.app?=   ${OTHER}",
                    481:                        "VAR.asg.def=    ${OTHER}",
                    482:                        "VAR.asg.asg=    ${OTHER}",
                    483:                        "VAR.asg.app=    ${OTHER}",
                    484:                        "VAR.app.def+=   ${OTHER}",
                    485:                        "VAR.app.asg+=   ${OTHER}",
                    486:                        "VAR.app.app+=   ${OTHER}"),
1.1       rillig    487:                include("included2.mk",
1.2       rillig    488:                        "VAR.def.def?=   ${OTHER}",
                    489:                        "VAR.def.asg=    ${OTHER}",
                    490:                        "VAR.def.app+=   ${OTHER}",
                    491:                        "VAR.asg.def?=   ${OTHER}",
                    492:                        "VAR.asg.asg=    ${OTHER}",
                    493:                        "VAR.asg.app+=   ${OTHER}",
                    494:                        "VAR.app.def?=   ${OTHER}",
                    495:                        "VAR.app.asg=    ${OTHER}",
                    496:                        "VAR.app.app+=   ${OTHER}"))
1.1       rillig    497:        mklines := get("including.mk")
                    498:
                    499:        NewRedundantScope().Check(mklines)
                    500:
                    501:        // Since the two included files are independent, there cannot be any
                    502:        // redundancies between them. These redundancies can only be discovered
                    503:        // when one of them includes the other.
                    504:        t.CheckOutputEmpty()
                    505: }
                    506:
                    507: func (s *Suite) Test_RedundantScope__independent_different_value(c *check.C) {
                    508:        t := s.Init(c)
                    509:
                    510:        // Only test the ?=, = and += operators since the others are ignored,
                    511:        // as of March 2019.
                    512:        include, get := t.SetUpHierarchy()
                    513:        include("including.mk",
                    514:                include("included1.mk",
1.2       rillig    515:                        "VAR.def.def?=   ${VALUE}",
                    516:                        "VAR.def.asg?=   ${VALUE}",
                    517:                        "VAR.def.app?=   ${VALUE}",
                    518:                        "VAR.asg.def=    ${VALUE}",
                    519:                        "VAR.asg.asg=    ${VALUE}",
                    520:                        "VAR.asg.app=    ${VALUE}",
                    521:                        "VAR.app.def+=   ${VALUE}",
                    522:                        "VAR.app.asg+=   ${VALUE}",
                    523:                        "VAR.app.app+=   ${VALUE}"),
1.1       rillig    524:                include("included2.mk",
1.2       rillig    525:                        "VAR.def.def?=   ${OTHER}",
                    526:                        "VAR.def.asg=    ${OTHER}",
                    527:                        "VAR.def.app+=   ${OTHER}",
                    528:                        "VAR.asg.def?=   ${OTHER}",
                    529:                        "VAR.asg.asg=    ${OTHER}",
                    530:                        "VAR.asg.app+=   ${OTHER}",
                    531:                        "VAR.app.def?=   ${OTHER}",
                    532:                        "VAR.app.asg=    ${OTHER}",
                    533:                        "VAR.app.app+=   ${OTHER}"))
1.1       rillig    534:        mklines := get("including.mk")
                    535:
                    536:        NewRedundantScope().Check(mklines)
                    537:
                    538:        // Since the two included files are independent, there cannot be any
                    539:        // redundancies between them. Redundancies can only be discovered
                    540:        // when one of them includes the other.
                    541:        t.CheckOutputEmpty()
                    542: }
                    543:
                    544: func (s *Suite) Test_RedundantScope__file_hierarchy(c *check.C) {
                    545:        t := s.Init(c)
                    546:
                    547:        include, get := t.SetUpHierarchy()
                    548:
                    549:        include("including.mk",
                    550:                include("other.mk",
1.2       rillig    551:                        "VAR=    other"),
1.1       rillig    552:                include("module.mk",
1.2       rillig    553:                        "VAR=    module",
1.1       rillig    554:                        include("version.mk",
1.2       rillig    555:                                "VAR=    version"),
1.1       rillig    556:                        include("env.mk",
1.2       rillig    557:                                "VAR=     env")))
1.1       rillig    558:
                    559:        NewRedundantScope().Check(get("including.mk"))
                    560:
                    561:        // No output since the included files are independent.
                    562:        t.CheckOutputEmpty()
                    563:
                    564:        NewRedundantScope().Check(get("other.mk"))
                    565:
                    566:        // No output since the file by itself in neither redundant nor
                    567:        // does it include any other file.
                    568:        t.CheckOutputEmpty()
                    569:
                    570:        NewRedundantScope().Check(get("module.mk"))
                    571:
                    572:        // No warning about env.mk because it is independent from version.mk.
                    573:        // Pkglint only produces warnings when it is very sure that the variable
                    574:        // definition is really redundant in all cases.
                    575:        //
                    576:        // One reason to not warn is that at the point where env.mk is evaluated,
                    577:        // version.mk had last written to the variable. Since version.mk is
                    578:        // independent from env.mk, there is nothing redundant here.
                    579:        // Pkglint doesn't do this, but it could.
                    580:        //
                    581:        // Another reason not to warn is that all locations where the variable has
                    582:        // ever been accessed are saved. And if the current location neither includes
                    583:        // all of the others nor is included by all of the others, there is at least
                    584:        // one access that is in an unrelated file. This is what pkglint does.
                    585:        t.CheckOutputLines(
                    586:                "WARN: module.mk:1: Variable VAR is overwritten in version.mk:1.")
                    587: }
                    588:
1.2       rillig    589: // The RedundantScope keeps track of the variable values. As a consequence,
                    590: // it reports the variable assignment in the last line as being redundant,
                    591: // instead of warning that it destroys the previous value.
                    592: func (s *Suite) Test_RedundantScope__assign_and_append_followed_by_assign(c *check.C) {
                    593:        t := s.Init(c)
                    594:
                    595:        mklines := t.NewMkLines("redundant.mk",
                    596:                "VAR=    first",
                    597:                "VAR+=   second",
                    598:                "VAR=    first second")
                    599:
                    600:        NewRedundantScope().Check(mklines)
                    601:
                    602:        t.CheckOutputLines(
                    603:                "NOTE: redundant.mk:3: Definition of VAR is redundant because of line 2.")
                    604: }
                    605:
                    606: // The redundancy analysis for a variable VAR is influenced by changes to
                    607: // each variable that is referenced by VAR. The exact details also depend
                    608: // on the assignment operators being used for VAR and OTHER.
                    609: func (s *Suite) Test_RedundantScope__referenced_variable_is_modified(c *check.C) {
                    610:        t := s.Init(c)
                    611:
                    612:        test := func(line1, line2, line3, line4 string, diagnostics ...string) {
                    613:                mklines := t.NewMkLines("filename.mk",
                    614:                        line1, line2, line3, line4)
                    615:
                    616:                NewRedundantScope().Check(mklines)
                    617:
                    618:                t.CheckOutput(diagnostics)
                    619:        }
                    620:
                    621:        test(
                    622:                "OTHER=  other-before",
                    623:                "VAR=    ${OTHER}",
                    624:                "OTHER?= other-after",
                    625:                "VAR=    ${OTHER}",
                    626:
                    627:                // TODO: "3: has no effect"
                    628:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    629:
                    630:        test(
                    631:                "OTHER=  other-before",
                    632:                "VAR=    ${OTHER}",
                    633:                "OTHER=  other-after",
                    634:                "VAR=    ${OTHER}",
                    635:
                    636:                // TODO: "3: overwrites",
                    637:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    638:
                    639:        test(
                    640:                "OTHER=  other-before",
                    641:                "VAR=    ${OTHER}",
                    642:                "OTHER+= other-after",
                    643:                "VAR=    ${OTHER}",
                    644:
                    645:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    646:
                    647:        test(
                    648:                "OTHER=  other-before",
                    649:                "VAR=    ${OTHER}",
                    650:                "OTHER:= other-after",
                    651:                "VAR=    ${OTHER}",
                    652:
                    653:                // TODO: "3: overwrites line 1"
                    654:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    655:
                    656:        test(
                    657:                "OTHER=  other-before",
                    658:                "VAR=    ${OTHER}",
                    659:                "OTHER!= other-after",
                    660:                "VAR=    ${OTHER}",
                    661:
                    662:                // TODO: "3: overwrites line 1",
                    663:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    664: }
                    665:
                    666: // The redundancy analysis for a variable VAR is influenced by changes to
                    667: // each variable that is referenced by VAR. The exact details also depend
                    668: // on the assignment operators being used for VAR and OTHER.
                    669: func (s *Suite) Test_RedundantScope__variable_referencing_another_is_modified(c *check.C) {
                    670:        t := s.Init(c)
                    671:
                    672:        test := func(line1, line2, line3, line4 string, diagnostics ...string) {
                    673:                mklines := t.NewMkLines("filename.mk",
                    674:                        line1, line2, line3, line4)
                    675:
                    676:                NewRedundantScope().Check(mklines)
                    677:
                    678:                t.CheckOutput(diagnostics)
                    679:        }
                    680:
                    681:        // In this test, the second line is tested for each operator.
                    682:
                    683:        test(
                    684:                "OTHER=  other-before",
                    685:                "VAR?=   ${OTHER}",
                    686:                "OTHER=  other-after",
                    687:                "VAR=    ${OTHER}",
                    688:
                    689:                // TODO: "3: overwrites line 1"
                    690:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    691:
                    692:        test(
                    693:                "OTHER=  other-before",
                    694:                "VAR=    ${OTHER}",
                    695:                "OTHER=  other-after",
                    696:                "VAR=    ${OTHER}",
                    697:
                    698:                // TODO: "3: overwrites",
                    699:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    700:
                    701:        test(
                    702:                "OTHER=  other-before",
                    703:                "VAR+=   ${OTHER}",
                    704:                "OTHER=  other-after",
                    705:                "VAR=    ${OTHER}",
                    706:
                    707:                // TODO: "3: overwrites",
                    708:                // The value from line 2 is prefixed by a space, therefore pkglint
                    709:                // issues a warning here instead of an "is redundant" note.
                    710:                "WARN: filename.mk:2: Variable VAR is overwritten in line 4.")
                    711:
                    712:        test(
                    713:                "OTHER=  other-before",
                    714:                "VAR:=   ${OTHER}",
                    715:                "OTHER=  other-after",
                    716:                "VAR=    ${OTHER}",
                    717:
                    718:                // As of March 2019, pkglint only looks at each variable in isolation.
                    719:                // In this case, to detect that the assignment in line 1 has no effect,
                    720:                // it's necessary to trace the assignment in line 2 and then see that
                    721:                // the VAR from line 2 is immediately overwritten in line 4.
                    722:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    723:
                    724:        test(
                    725:                "OTHER=  other-before",
                    726:                "VAR=    ${OTHER}",
                    727:                "OTHER!= other-after",
                    728:                "VAR=    ${OTHER}",
                    729:
                    730:                "NOTE: filename.mk:4: Definition of VAR is redundant because of line 2.")
                    731: }
                    732:
1.4       rillig    733: func (s *Suite) Test_RedundantScope__incomplete_then_default(c *check.C) {
                    734:        t := s.Init(c)
                    735:
                    736:        include, get := t.SetUpHierarchy()
                    737:
                    738:        include("including.mk",
                    739:                ".if ${OPSYS} == NetBSD",
                    740:                "VAR=\tNetBSD",
                    741:                ".elif ${OPSYS} == FreeBSD",
                    742:                "VAR=\tFreeBSD",
                    743:                ".endif",
                    744:                "",
                    745:                "VAR?=\tdefault")
                    746:
                    747:        mklines := get("including.mk")
                    748:
                    749:        NewRedundantScope().Check(mklines)
                    750:
                    751:        t.CheckOutputEmpty()
                    752: }
                    753:
                    754: func (s *Suite) Test_RedundantScope__complete_then_default(c *check.C) {
                    755:        t := s.Init(c)
                    756:
                    757:        include, get := t.SetUpHierarchy()
                    758:
                    759:        include("including.mk",
                    760:                ".if ${OPSYS} == NetBSD",
                    761:                "VAR=\tNetBSD",
                    762:                ".else",
                    763:                "VAR=\tFreeBSD",
                    764:                ".endif",
                    765:                "",
                    766:                "VAR?=\tdefault")
                    767:
                    768:        mklines := get("including.mk")
                    769:
                    770:        NewRedundantScope().Check(mklines)
                    771:
                    772:        // TODO: Pkglint could know that the ?= is redundant because VAR is
                    773:        //  definitely assigned.
                    774:        t.CheckOutputEmpty()
                    775: }
                    776:
                    777: func (s *Suite) Test_RedundantScope__conditional_then_override(c *check.C) {
                    778:        t := s.Init(c)
                    779:
                    780:        include, get := t.SetUpHierarchy()
                    781:
                    782:        include("including.mk",
                    783:                ".if ${OPSYS} == NetBSD",
                    784:                "VAR=\tNetBSD",
                    785:                ".else",
                    786:                "VAR=\tFreeBSD",
                    787:                ".endif",
                    788:                "",
                    789:                "VAR=\tdefault")
                    790:
                    791:        mklines := get("including.mk")
                    792:
                    793:        NewRedundantScope().Check(mklines)
                    794:
                    795:        // TODO: Pkglint could know that no matter which branch is taken,
                    796:        //  the variable will be overwritten in the last line.
                    797:        t.CheckOutputEmpty()
                    798: }
                    799:
                    800: func (s *Suite) Test_RedundantScope__set_then_conditional(c *check.C) {
                    801:        t := s.Init(c)
                    802:
                    803:        include, get := t.SetUpHierarchy()
                    804:
                    805:        include("including.mk",
                    806:                "VAR=\tdefault",
                    807:                "",
                    808:                ".if ${OPSYS} == NetBSD",
                    809:                "VAR=\tNetBSD",
                    810:                ".else",
                    811:                "VAR=\tFreeBSD",
                    812:                ".endif")
                    813:
                    814:        mklines := get("including.mk")
                    815:
                    816:        NewRedundantScope().Check(mklines)
                    817:
                    818:        // TODO: Pkglint could know that no matter which branch is taken,
                    819:        //  one of the branches will overwrite the assignment from line 1.
                    820:        t.CheckOutputEmpty()
                    821: }
                    822:
                    823: func (s *Suite) Test_RedundantScope__branch_with_set_then_set(c *check.C) {
                    824:        t := s.Init(c)
                    825:
                    826:        include, get := t.SetUpHierarchy()
                    827:
                    828:        include("including.mk",
                    829:                ".if ${OPSYS} == NetBSD",
                    830:                "VAR=\tfirst",
                    831:                "VAR=\tsecond",
                    832:                ".endif")
                    833:
                    834:        mklines := get("including.mk")
                    835:
                    836:        NewRedundantScope().Check(mklines)
                    837:
                    838:        // TODO: Pkglint could know that the second assignment overwrites the
                    839:        //  first assignment since they are in the same basic block.
                    840:        t.CheckOutputEmpty()
                    841: }
                    842:
1.1       rillig    843: // FIXME: Continue the systematic redundancy tests.
                    844: //
                    845: // Tests where the variables are defined in a .for loop that might not be
                    846: // evaluated at all.
                    847: //
                    848: // Tests where files are included conditionally and additionally have conditional
                    849: // sections, arbitrarily nested.
                    850: //
                    851: // Tests that show how to suppress the notes about redundant assignments
                    852: // and overwritten variables. The explanation must be helpful.
                    853: //
                    854: // Tests for dynamic variable assignments. For example BUILD_DIRS.NetBSD may
                    855: // be modified by any assignment of the form BUILD_DIRS.${var} or even ${var}.
                    856: // Without further analysis, pkglint cannot report redundancy warnings for any
                    857: // package that uses such variable assignments.
1.2       rillig    858: //
                    859: // Tests for variables with modifiers, such as ${VAR:Uundef}, ${VAR:Mpattern},
                    860: // ${command:sh}, ${command::=value}.
                    861: //
                    862: // A test that compares a package with the default values from mk/defaults/mk.conf.
                    863: // A package doesn't need to override these defaults, and the redundancy check
                    864: // should notify the package author of this redundancy.
1.1       rillig    865:
                    866: func (s *Suite) Test_RedundantScope__override_after_including(c *check.C) {
                    867:        t := s.Init(c)
                    868:
1.2       rillig    869:        include, get := t.SetUpHierarchy()
                    870:        include("including.mk",
                    871:                include("included.mk",
                    872:                        "OVERRIDE=       previous value",
                    873:                        "REDUNDANT=      redundant"),
                    874:                "OVERRIDE=       overridden value",
                    875:                "REDUNDANT=      redundant")
                    876:
                    877:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig    878:
                    879:        t.CheckOutputLines(
                    880:                "NOTE: including.mk:3: Definition of REDUNDANT is redundant because of included.mk:2.")
                    881: }
                    882:
                    883: func (s *Suite) Test_RedundantScope__redundant_assign_after_including(c *check.C) {
                    884:        t := s.Init(c)
                    885:
1.2       rillig    886:        include, get := t.SetUpHierarchy()
                    887:        include("including.mk",
                    888:                include("included.mk",
                    889:                        "REDUNDANT=      redundant"),
                    890:                "REDUNDANT=      redundant")
                    891:
                    892:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig    893:
                    894:        t.CheckOutputLines(
                    895:                "NOTE: including.mk:2: Definition of REDUNDANT is redundant because of included.mk:1.")
                    896: }
                    897:
                    898: func (s *Suite) Test_RedundantScope__override_in_Makefile_after_including(c *check.C) {
                    899:        t := s.Init(c)
                    900:
1.2       rillig    901:        include, get := t.SetUpHierarchy()
                    902:        include("Makefile",
                    903:                include("module.mk",
                    904:                        "VAR=    value ${OTHER}",
                    905:                        "VAR?=   value ${OTHER}",
                    906:                        "VAR=    new value"),
                    907:                "VAR=    the package may overwrite variables from other files")
1.1       rillig    908:
                    909:        // XXX: The warnings from here are not in the same order as the other warnings.
                    910:        // XXX: There may be some warnings for the same file separated by warnings for other files.
1.2       rillig    911:        NewRedundantScope().Check(get("Makefile"))
1.1       rillig    912:
                    913:        // No warning for VAR=... in Makefile since it makes sense to have common files
                    914:        // with default values for variables, overriding some of them in each package.
                    915:        t.CheckOutputLines(
                    916:                "NOTE: module.mk:2: Default assignment of VAR has no effect because of line 1.",
                    917:                "WARN: module.mk:2: Variable VAR is overwritten in line 3.")
                    918: }
                    919:
                    920: func (s *Suite) Test_RedundantScope__default_value_definitely_unused(c *check.C) {
                    921:        t := s.Init(c)
1.2       rillig    922:
1.1       rillig    923:        mklines := t.NewMkLines("module.mk",
1.2       rillig    924:                "VAR=    value ${OTHER}",
                    925:                "VAR?=   different value")
1.1       rillig    926:
                    927:        NewRedundantScope().Check(mklines)
                    928:
                    929:        // A default assignment after an unconditional assignment is redundant.
                    930:        // Even more so when the variable is not used between the two assignments.
                    931:        t.CheckOutputLines(
                    932:                "NOTE: module.mk:2: Default assignment of VAR has no effect because of line 1.")
                    933: }
                    934:
                    935: func (s *Suite) Test_RedundantScope__default_value_overridden(c *check.C) {
                    936:        t := s.Init(c)
1.2       rillig    937:
1.1       rillig    938:        mklines := t.NewMkLines("module.mk",
1.2       rillig    939:                "VAR?=   default value",
                    940:                "VAR=    overridden value")
1.1       rillig    941:
                    942:        NewRedundantScope().Check(mklines)
                    943:
                    944:        t.CheckOutputLines(
                    945:                "WARN: module.mk:1: Variable VAR is overwritten in line 2.")
                    946: }
                    947:
                    948: func (s *Suite) Test_RedundantScope__overwrite_same_value(c *check.C) {
                    949:        t := s.Init(c)
1.2       rillig    950:
1.1       rillig    951:        mklines := t.NewMkLines("module.mk",
1.2       rillig    952:                "VAR=    value ${OTHER}",
                    953:                "VAR=    value ${OTHER}")
1.1       rillig    954:
                    955:        NewRedundantScope().Check(mklines)
                    956:
                    957:        t.CheckOutputLines(
                    958:                "NOTE: module.mk:2: Definition of VAR is redundant because of line 1.")
                    959: }
                    960:
                    961: func (s *Suite) Test_RedundantScope__conditional_overwrite(c *check.C) {
                    962:        t := s.Init(c)
1.2       rillig    963:
1.1       rillig    964:        mklines := t.NewMkLines("module.mk",
1.2       rillig    965:                "VAR=    default",
1.1       rillig    966:                ".if ${OPSYS} == NetBSD",
1.2       rillig    967:                "VAR=    opsys",
1.1       rillig    968:                ".endif")
                    969:
                    970:        NewRedundantScope().Check(mklines)
                    971:
                    972:        t.CheckOutputEmpty()
                    973: }
                    974:
                    975: func (s *Suite) Test_RedundantScope__overwrite_inside_conditional(c *check.C) {
                    976:        t := s.Init(c)
1.2       rillig    977:
1.1       rillig    978:        mklines := t.NewMkLines("module.mk",
1.2       rillig    979:                "VAR=    generic",
1.1       rillig    980:                ".if ${OPSYS} == NetBSD",
1.2       rillig    981:                "VAR=    ignored",
                    982:                "VAR=    overwritten",
1.1       rillig    983:                ".endif")
                    984:
                    985:        NewRedundantScope().Check(mklines)
                    986:
                    987:        // TODO: expected a warning "WARN: module.mk:4: line 3 is ignored"
                    988:        // Since line 3 and line 4 are in the same basic block, line 3 is definitely ignored.
                    989:        t.CheckOutputEmpty()
                    990: }
                    991:
                    992: func (s *Suite) Test_RedundantScope__conditionally_include(c *check.C) {
                    993:        t := s.Init(c)
1.2       rillig    994:
                    995:        include, get := t.SetUpHierarchy()
                    996:        include("module.mk",
                    997:                "VAR=    generic",
1.1       rillig    998:                ".if ${OPSYS} == NetBSD",
1.2       rillig    999:                include("included.mk",
                   1000:                        "VAR=    ignored",
                   1001:                        "VAR=    overwritten"),
1.1       rillig   1002:                ".endif")
                   1003:
1.2       rillig   1004:        NewRedundantScope().Check(get("module.mk"))
1.1       rillig   1005:
                   1006:        // TODO: expected a warning "WARN: module.mk:4: line 3 is ignored"
                   1007:        //  Since line 3 and line 4 are in the same basic block, line 3 is definitely ignored.
                   1008:        t.CheckOutputEmpty()
                   1009: }
                   1010:
                   1011: func (s *Suite) Test_RedundantScope__conditional_default(c *check.C) {
                   1012:        t := s.Init(c)
1.2       rillig   1013:
1.1       rillig   1014:        mklines := t.NewMkLines("module.mk",
1.2       rillig   1015:                "VAR=    default",
1.1       rillig   1016:                ".if ${OPSYS} == NetBSD",
1.2       rillig   1017:                "VAR?=   opsys",
1.1       rillig   1018:                ".endif")
                   1019:
                   1020:        NewRedundantScope().Check(mklines)
                   1021:
1.2       rillig   1022:        // TODO: WARN: module.mk:3: The value \"opsys\" will never be assigned
                   1023:        //  to VAR because it is defined unconditionally in line 1.
1.1       rillig   1024:        t.CheckOutputEmpty()
                   1025: }
                   1026:
                   1027: // These warnings are precise and accurate since the value of VAR is not used between line 2 and 4.
                   1028: func (s *Suite) Test_RedundantScope__overwrite_same_variable_different_value(c *check.C) {
                   1029:        t := s.Init(c)
1.2       rillig   1030:
1.1       rillig   1031:        mklines := t.NewMkLines("module.mk",
1.2       rillig   1032:                "OTHER=  value before",
                   1033:                "VAR=    value ${OTHER}",
                   1034:                "OTHER=  value after",
                   1035:                "VAR=    value ${OTHER}")
1.1       rillig   1036:
                   1037:        NewRedundantScope().Check(mklines)
                   1038:
                   1039:        // Strictly speaking, line 1 is redundant because OTHER is not evaluated
                   1040:        // at load time and then immediately overwritten in line 3. If the operator
                   1041:        // in line 2 were a := instead of a =, the situation would be clear.
                   1042:        // Pkglint doesn't warn about the redundancy in line 1 because it prefers
                   1043:        // to omit warnings instead of giving wrong advice.
                   1044:        t.CheckOutputLines(
                   1045:                "NOTE: module.mk:4: Definition of VAR is redundant because of line 2.")
                   1046: }
                   1047:
                   1048: func (s *Suite) Test_RedundantScope__overwrite_different_value_used_between(c *check.C) {
                   1049:        t := s.Init(c)
1.2       rillig   1050:
1.1       rillig   1051:        mklines := t.NewMkLines("module.mk",
1.2       rillig   1052:                "OTHER=          value before",
                   1053:                "VAR=            value ${OTHER}",
1.1       rillig   1054:
                   1055:                // VAR is used here at load time, therefore it must be defined at this point.
                   1056:                // At this point, VAR uses the \"before\" value of OTHER.
1.2       rillig   1057:                "RESULT1:=       ${VAR}",
1.1       rillig   1058:
1.2       rillig   1059:                "OTHER=          value after",
1.1       rillig   1060:
                   1061:                // VAR is used here again at load time, this time using the \"after\" value of OTHER.
1.2       rillig   1062:                "RESULT2:=       ${VAR}",
1.1       rillig   1063:
                   1064:                // Still this definition is redundant.
1.2       rillig   1065:                "VAR=            value ${OTHER}")
1.1       rillig   1066:
                   1067:        NewRedundantScope().Check(mklines)
                   1068:
                   1069:        // There is nothing redundant here. Each write is followed by a
                   1070:        // corresponding read, except for the last one. That is ok though
                   1071:        // because in pkgsrc the last action of a package is to include
                   1072:        // bsd.pkg.mk, which reads almost all variables.
                   1073:        t.CheckOutputEmpty()
                   1074: }
                   1075:
                   1076: func (s *Suite) Test_RedundantScope__procedure_call_to_noop(c *check.C) {
                   1077:        t := s.Init(c)
                   1078:
                   1079:        include, get := t.SetUpHierarchy()
                   1080:        include("mk/pthread.buildlink3.mk",
                   1081:                "CHECK_BUILTIN.pthread:= yes",
                   1082:                include("pthread.builtin.mk",
                   1083:                        "# Nothing happens here."),
                   1084:                "CHECK_BUILTIN.pthread:= no")
                   1085:
                   1086:        NewRedundantScope().Check(get("mk/pthread.buildlink3.mk"))
                   1087:
                   1088:        t.CheckOutputLines(
                   1089:                "WARN: mk/pthread.buildlink3.mk:1: Variable CHECK_BUILTIN.pthread is overwritten in line 3.")
                   1090: }
                   1091:
                   1092: func (s *Suite) Test_RedundantScope__procedure_call_implemented(c *check.C) {
                   1093:        t := s.Init(c)
                   1094:
                   1095:        include, get := t.SetUpHierarchy()
                   1096:        include("mk/pthread.buildlink3.mk",
                   1097:                "CHECK_BUILTIN.pthread:= yes",
                   1098:                include("pthread.builtin.mk",
                   1099:                        "CHECK_BUILTIN.pthread?= no",
                   1100:                        ".if !empty(CHECK_BUILTIN.pthread:M[Nn][Oo])",
                   1101:                        ".endif"),
                   1102:                "CHECK_BUILTIN.pthread:= no")
                   1103:
                   1104:        NewRedundantScope().Check(get("mk/pthread.buildlink3.mk"))
                   1105:
                   1106:        // This test is a bit unrealistic. It wrongly assumes that all files from
                   1107:        // an .include directive are actually included by pkglint.
                   1108:        //
                   1109:        // See Package.readMakefile/handleIncludeLine/skip.
                   1110:        t.CheckOutputEmpty()
                   1111: }
                   1112:
                   1113: func (s *Suite) Test_RedundantScope__procedure_call_implemented_package(c *check.C) {
                   1114:        t := s.Init(c)
                   1115:
                   1116:        t.SetUpPkgsrc()
                   1117:        t.SetUpPackage("devel/gettext-lib")
                   1118:        t.SetUpPackage("x11/Xaos",
                   1119:                ".include \"../../devel/gettext-lib/buildlink3.mk\"")
                   1120:        t.CreateFileLines("devel/gettext-lib/builtin.mk",
1.5       rillig   1121:                MkCvsID,
1.1       rillig   1122:                "",
                   1123:                ".include \"../../mk/bsd.fast.prefs.mk\"",
                   1124:                "",
1.2       rillig   1125:                "CHECK_BUILTIN.gettext?= no",
1.1       rillig   1126:                ".if !empty(CHECK_BUILTIN.gettext:M[nN][oO])",
                   1127:                ".endif")
                   1128:        t.CreateFileLines("devel/gettext-lib/buildlink3.mk",
1.5       rillig   1129:                MkCvsID,
1.2       rillig   1130:                "CHECK_BUILTIN.gettext:= yes",
1.1       rillig   1131:                ".include \"builtin.mk\"",
1.2       rillig   1132:                "CHECK_BUILTIN.gettext:= no")
1.3       rillig   1133:        t.FinishSetUp()
1.1       rillig   1134:
                   1135:        // Checking x11/Xaos instead of devel/gettext-lib avoids warnings
                   1136:        // about the minimal buildlink3.mk file.
                   1137:        G.Check(t.File("x11/Xaos"))
                   1138:
                   1139:        // There is nothing redundant here.
                   1140:        // Up to March 2019, pkglint didn't pass the correct pathnames to Package.included,
                   1141:        // which triggered a wrong note here.
                   1142:        t.CheckOutputEmpty()
                   1143: }
                   1144:
                   1145: func (s *Suite) Test_RedundantScope__procedure_call_infrastructure(c *check.C) {
                   1146:        t := s.Init(c)
                   1147:
                   1148:        t.SetUpPackage("x11/alacarte",
                   1149:                ".include \"../../mk/pthread.buildlink3.mk\"")
                   1150:        t.CreateFileLines("mk/pthread.buildlink3.mk",
1.5       rillig   1151:                MkCvsID,
1.2       rillig   1152:                "CHECK_BUILTIN.gettext:= yes",
1.1       rillig   1153:                ".include \"pthread.builtin.mk\"",
1.2       rillig   1154:                "CHECK_BUILTIN.gettext:= no")
1.1       rillig   1155:        t.CreateFileLines("mk/pthread.builtin.mk",
1.5       rillig   1156:                MkCvsID,
1.2       rillig   1157:                "CHECK_BUILTIN.gettext?= no",
1.1       rillig   1158:                ".if !empty(CHECK_BUILTIN.gettext:M[nN][oO])",
                   1159:                ".endif")
1.3       rillig   1160:        t.FinishSetUp()
1.1       rillig   1161:
                   1162:        G.Check(t.File("x11/alacarte"))
                   1163:
                   1164:        // There is nothing redundant here.
                   1165:        //
                   1166:        // 1. pthread.buildlink3.mk sets the variable
                   1167:        // 2. pthread.builtin.mk assigns it a default value
                   1168:        //    (which is common practice)
                   1169:        // 3. pthread.builtin.mk then reads it
                   1170:        //    (which marks the next write as non-redundant)
                   1171:        // 4. pthread.buildlink3.mk sets the variable again
                   1172:        //    (this is considered neither overwriting nor redundant)
                   1173:        //
                   1174:        // Up to March 2019, pkglint complained:
                   1175:        //
                   1176:        // WARN: ~/mk/pthread.buildlink3.mk:2:
                   1177:        //     Variable CHECK_BUILTIN.gettext is overwritten in line 4.
                   1178:        //
                   1179:        // The cause for the warning is that when including files from the
                   1180:        // infrastructure, pkglint only includes the outermost level of files.
                   1181:        // If an infrastructure file includes another infrastructure file,
                   1182:        // pkglint skips that, for performance reasons.
                   1183:        //
                   1184:        // This optimization effectively made the .include for pthread.builtin.mk
                   1185:        // a no-op, therefore it was correct to issue a warning here.
                   1186:        //
                   1187:        // Since this warning is wrong, in March 2019 another special rule has
                   1188:        // been added to Package.readMakefile.handleIncludeLine.skip saying that
                   1189:        // including a buildlink3.mk file also includes the corresponding
                   1190:        // builtin.mk file.
                   1191:        t.CheckOutputEmpty()
                   1192: }
                   1193:
                   1194: func (s *Suite) Test_RedundantScope__shell_and_eval(c *check.C) {
                   1195:        t := s.Init(c)
1.2       rillig   1196:
1.1       rillig   1197:        mklines := t.NewMkLines("module.mk",
1.2       rillig   1198:                "VAR:=    value ${OTHER}",
                   1199:                "VAR!=    value ${OTHER}")
1.1       rillig   1200:
                   1201:        NewRedundantScope().Check(mklines)
                   1202:
                   1203:        // As of November 2018, pkglint doesn't check redundancies that involve the := or != operators.
                   1204:        //
                   1205:        // What happens here is:
                   1206:        //
                   1207:        // Line 1 evaluates OTHER at load time.
                   1208:        // Line 1 assigns its value to VAR.
                   1209:        // Line 2 evaluates OTHER at load time.
                   1210:        // Line 2 passes its value through the shell and assigns the result to VAR.
                   1211:        //
                   1212:        // Since VAR is defined in line 1, not used afterwards and overwritten in line 2, it is redundant.
                   1213:        // Well, not quite, because evaluating ${OTHER} might have side-effects from :sh or ::= modifiers,
                   1214:        // but these are so rare that they are frowned upon and are not considered by pkglint.
                   1215:        //
                   1216:        // Expected result:
                   1217:        // WARN: module.mk:2: Previous definition of VAR in line 1 is unused.
                   1218:
                   1219:        t.CheckOutputEmpty()
                   1220: }
                   1221:
                   1222: func (s *Suite) Test_RedundantScope__shell_and_eval_literal(c *check.C) {
                   1223:        t := s.Init(c)
1.2       rillig   1224:
1.1       rillig   1225:        mklines := t.NewMkLines("module.mk",
1.2       rillig   1226:                "VAR:=    value",
                   1227:                "VAR!=    value")
1.1       rillig   1228:
                   1229:        NewRedundantScope().Check(mklines)
                   1230:
                   1231:        // Even when := is used with a literal value (which is usually
                   1232:        // only done for procedure calls), the shell evaluation can have
                   1233:        // so many different side effects that pkglint cannot reliably
                   1234:        // help in this situation.
                   1235:        //
                   1236:        // TODO: Why not? The evaluation in line 1 is trivial to analyze.
                   1237:        t.CheckOutputEmpty()
                   1238: }
                   1239:
                   1240: func (s *Suite) Test_RedundantScope__included_OPSYS_variable(c *check.C) {
                   1241:        t := s.Init(c)
                   1242:
                   1243:        t.SetUpPackage("category/package",
                   1244:                ".include \"../../category/dependency/buildlink3.mk\"",
1.2       rillig   1245:                "CONFIGURE_ARGS+=        one",
                   1246:                "CONFIGURE_ARGS=         two",
                   1247:                "CONFIGURE_ARGS+=        three")
1.1       rillig   1248:        t.SetUpPackage("category/dependency")
1.10    ! rillig   1249:        t.CreateFileBuildlink3("category/dependency/buildlink3.mk")
1.1       rillig   1250:        t.CreateFileLines("category/dependency/builtin.mk",
1.5       rillig   1251:                MkCvsID,
1.2       rillig   1252:                "CONFIGURE_ARGS.Darwin+= darwin")
1.3       rillig   1253:        t.FinishSetUp()
1.1       rillig   1254:
                   1255:        G.Check(t.File("category/package"))
                   1256:
                   1257:        t.CheckOutputLines(
                   1258:                "WARN: ~/category/package/Makefile:21: Variable CONFIGURE_ARGS is overwritten in line 22.")
                   1259: }
                   1260:
                   1261: func (s *Suite) Test_RedundantScope__if_then_else(c *check.C) {
                   1262:        t := s.Init(c)
                   1263:
1.2       rillig   1264:        mklines := t.NewMkLines("if-then-else.mk",
1.1       rillig   1265:                ".if exists(${FILE})",
1.2       rillig   1266:                "OS=     NetBSD",
1.1       rillig   1267:                ".else",
1.2       rillig   1268:                "OS=     OTHER",
1.1       rillig   1269:                ".endif")
                   1270:
                   1271:        NewRedundantScope().Check(mklines)
                   1272:
                   1273:        // These two definitions are of course not redundant since they happen in
                   1274:        // different branches of the same .if statement.
                   1275:        t.CheckOutputEmpty()
                   1276: }
                   1277:
                   1278: func (s *Suite) Test_RedundantScope__if_then_else_without_variable(c *check.C) {
                   1279:        t := s.Init(c)
                   1280:
1.2       rillig   1281:        mklines := t.NewMkLines("if-then-else.mk",
1.1       rillig   1282:                ".if exists(/nonexistent)",
1.2       rillig   1283:                "IT=     exists",
1.1       rillig   1284:                ".else",
1.2       rillig   1285:                "IT=     doesn't exist",
1.1       rillig   1286:                ".endif")
                   1287:
                   1288:        NewRedundantScope().Check(mklines)
                   1289:
                   1290:        // These two definitions are of course not redundant since they happen in
                   1291:        // different branches of the same .if statement.
                   1292:        // Even though the .if condition does not refer to any variables,
                   1293:        // this still means that the variable assignments are conditional.
                   1294:        t.CheckOutputEmpty()
                   1295: }
                   1296:
                   1297: func (s *Suite) Test_RedundantScope__append_then_default(c *check.C) {
                   1298:        t := s.Init(c)
                   1299:
1.2       rillig   1300:        mklines := t.NewMkLines("append-then-default.mk",
                   1301:                "VAR+=   value",
                   1302:                "VAR?=   value")
1.1       rillig   1303:
                   1304:        NewRedundantScope().Check(mklines)
                   1305:
                   1306:        t.CheckOutputLines(
1.2       rillig   1307:                "NOTE: append-then-default.mk:2: Default assignment of VAR has no effect because of line 1.")
1.1       rillig   1308: }
                   1309:
                   1310: func (s *Suite) Test_RedundantScope__assign_then_default_in_same_file(c *check.C) {
                   1311:        t := s.Init(c)
                   1312:
1.2       rillig   1313:        mklines := t.NewMkLines("assign-then-default.mk",
                   1314:                "VAR=    value",
                   1315:                "VAR?=   value")
1.1       rillig   1316:
                   1317:        NewRedundantScope().Check(mklines)
                   1318:
                   1319:        t.CheckOutputLines(
1.2       rillig   1320:                "NOTE: assign-then-default.mk:2: " +
                   1321:                        "Default assignment of VAR has no effect because of line 1.")
1.1       rillig   1322: }
                   1323:
                   1324: func (s *Suite) Test_RedundantScope__eval_then_eval(c *check.C) {
                   1325:        t := s.Init(c)
                   1326:
1.2       rillig   1327:        mklines := t.NewMkLines("filename.mk",
                   1328:                "VAR:=   value",
                   1329:                "VAR:=   value",
                   1330:                "VAR:=   other")
1.1       rillig   1331:
                   1332:        NewRedundantScope().Check(mklines)
                   1333:
                   1334:        t.CheckOutputLines(
1.10    ! rillig   1335:                "NOTE: filename.mk:2: Definition of VAR is redundant because of line 1.",
1.2       rillig   1336:                "WARN: filename.mk:2: Variable VAR is overwritten in line 3.")
1.1       rillig   1337: }
                   1338:
                   1339: func (s *Suite) Test_RedundantScope__shell_then_assign(c *check.C) {
                   1340:        t := s.Init(c)
                   1341:
1.2       rillig   1342:        mklines := t.NewMkLines("filename.mk",
                   1343:                "VAR!=   echo echo",
                   1344:                "VAR=    echo echo")
1.1       rillig   1345:
                   1346:        NewRedundantScope().Check(mklines)
                   1347:
                   1348:        // Although the two variable assignments look very similar, they do
                   1349:        // something entirely different. The first executes the echo command,
                   1350:        // and the second just assigns a string. Therefore the actual variable
                   1351:        // values are different, and the second assignment is not redundant.
                   1352:        // It assigns a different value. Nevertheless, the shell command is
                   1353:        // redundant and can be removed since its result is never used.
                   1354:        t.CheckOutputLines(
1.2       rillig   1355:                "WARN: filename.mk:1: Variable VAR is overwritten in line 2.")
1.1       rillig   1356: }
                   1357:
                   1358: func (s *Suite) Test_RedundantScope__shell_then_read_then_assign(c *check.C) {
                   1359:        t := s.Init(c)
                   1360:
                   1361:        mklines := t.SetUpFileMkLines("filename.mk",
1.2       rillig   1362:                "VAR!=           echo echo",
                   1363:                "OUTPUT:=        ${VAR}",
                   1364:                "VAR=            echo echo")
1.1       rillig   1365:
                   1366:        NewRedundantScope().Check(mklines)
                   1367:
                   1368:        // No warning since the value is used in-between.
                   1369:        t.CheckOutputEmpty()
                   1370: }
                   1371:
                   1372: func (s *Suite) Test_RedundantScope__assign_then_default_in_included_file(c *check.C) {
                   1373:        t := s.Init(c)
                   1374:
1.2       rillig   1375:        include, get := t.SetUpHierarchy()
                   1376:        include("assign-then-default.mk",
                   1377:                "VAR=    value",
                   1378:                include("included.mk",
                   1379:                        "VAR?=    value"))
1.1       rillig   1380:
1.2       rillig   1381:        NewRedundantScope().Check(get("assign-then-default.mk"))
1.1       rillig   1382:
1.2       rillig   1383:        // If assign-then-default.mk:1 were deleted, VAR would still have the same value.
1.1       rillig   1384:        t.CheckOutputLines(
1.2       rillig   1385:                "NOTE: assign-then-default.mk:1: Definition of VAR is redundant because of included.mk:1.")
1.1       rillig   1386: }
                   1387:
                   1388: func (s *Suite) Test_RedundantScope__conditionally_included_file(c *check.C) {
                   1389:        t := s.Init(c)
                   1390:
1.2       rillig   1391:        include, get := t.SetUpHierarchy()
                   1392:        include("including.mk",
                   1393:                "VAR=    value",
1.1       rillig   1394:                ".if ${COND}",
1.2       rillig   1395:                include("included.mk",
                   1396:                        "VAR?=   value"),
1.1       rillig   1397:                ".endif")
                   1398:
1.2       rillig   1399:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig   1400:
                   1401:        // The assignment in including.mk:2 is only redundant if included.mk is actually included.
                   1402:        // Therefore both included.mk:2 nor including.mk:2 are relevant.
                   1403:        t.CheckOutputEmpty()
                   1404: }
                   1405:
                   1406: func (s *Suite) Test_RedundantScope__procedure_parameters(c *check.C) {
                   1407:        t := s.Init(c)
                   1408:
1.2       rillig   1409:        // TODO: make Tester.SetUpHierarchy accept a file multiple times.
1.1       rillig   1410:        t.CreateFileLines("mk/pkg-build-options.mk",
1.2       rillig   1411:                "USED:=  ${pkgbase}")
1.1       rillig   1412:        t.CreateFileLines("including.mk",
1.2       rillig   1413:                "pkgbase= package1",
1.1       rillig   1414:                ".include \"mk/pkg-build-options.mk\"",
                   1415:                "",
1.2       rillig   1416:                "pkgbase= package2",
1.1       rillig   1417:                ".include \"mk/pkg-build-options.mk\"",
                   1418:                "",
1.2       rillig   1419:                "pkgbase= package3",
1.1       rillig   1420:                ".include \"mk/pkg-build-options.mk\"")
                   1421:        mklines := t.LoadMkInclude("including.mk")
                   1422:
                   1423:        NewRedundantScope().Check(mklines)
                   1424:
                   1425:        // This variable is not overwritten since it is used in-between
                   1426:        // by the included file.
                   1427:        t.CheckOutputEmpty()
                   1428: }
                   1429:
1.10    ! rillig   1430: func (s *Suite) Test_RedundantScope__infra(c *check.C) {
        !          1431:        t := s.Init(c)
        !          1432:
        !          1433:        t.CreateFileLines("mk/bsd.options.mk",
        !          1434:                "PKG_OPTIONS:=\t# empty",
        !          1435:                "PKG_OPTIONS=\t# empty")
        !          1436:        t.CreateFileLines("options.mk",
        !          1437:                "OUTSIDE:=\t# empty",
        !          1438:                "OUTSIDE=\t# empty",
        !          1439:                ".include \"mk/bsd.options.mk\"")
        !          1440:
        !          1441:        test := func(diagnostics ...string) {
        !          1442:                mklines := t.LoadMkInclude("options.mk")
        !          1443:                scope := NewRedundantScope()
        !          1444:                scope.IsRelevant = func(mkline *MkLine) bool {
        !          1445:                        // See checkfilePackageMakefile.
        !          1446:                        if !G.Infrastructure && !G.Opts.CheckGlobal {
        !          1447:                                return !G.Pkgsrc.IsInfra(mkline.Filename)
        !          1448:                        }
        !          1449:                        return true
        !          1450:                }
        !          1451:
        !          1452:                scope.Check(mklines)
        !          1453:
        !          1454:                // No note about the redundant variable assignment in bsd.options.mk
        !          1455:                // because it is part of the infrastructure, which is filtered out.
        !          1456:                t.CheckOutput(diagnostics)
        !          1457:        }
        !          1458:
        !          1459:        test(
        !          1460:                "NOTE: ~/options.mk:2: " +
        !          1461:                        "Definition of OUTSIDE is redundant because of line 1.")
        !          1462:
        !          1463:        t.SetUpCommandLine("-Cglobal")
        !          1464:
        !          1465:        test(
        !          1466:                "NOTE: ~/options.mk:2: "+
        !          1467:                        "Definition of OUTSIDE is redundant because of line 1.",
        !          1468:                "NOTE: ~/mk/bsd.options.mk:2: "+
        !          1469:                        "Definition of PKG_OPTIONS is redundant because of line 1.")
        !          1470: }
        !          1471:
1.7       rillig   1472: // Branch coverage for info.vari.IsConstant(). The other tests typically
1.1       rillig   1473: // make a variable non-constant by adding conditional assignments between
                   1474: // .if/.endif. But there are other ways. The output of shell commands is
                   1475: // unpredictable for pkglint (as of March 2019), therefore it treats these
                   1476: // variables as non-constant.
                   1477: func (s *Suite) Test_RedundantScope_handleVarassign__shell_followed_by_default(c *check.C) {
                   1478:        t := s.Init(c)
                   1479:
                   1480:        include, get := t.SetUpHierarchy()
                   1481:        include("including.mk",
1.2       rillig   1482:                "VAR!=   echo 'hello, world'",
1.1       rillig   1483:                include("included.mk",
1.2       rillig   1484:                        "VAR?=   hello world"))
1.1       rillig   1485:
                   1486:        NewRedundantScope().Check(get("including.mk"))
                   1487:
                   1488:        // If pkglint should ever learn to interpret simple shell commands, there
                   1489:        // should be a warning for including.mk:2 that the shell command generates
                   1490:        // the default value.
                   1491:        t.CheckOutputEmpty()
                   1492: }
                   1493:
1.7       rillig   1494: func (s *Suite) Test_RedundantScope_handleVarassign__overwrite_definition_from_included_file(c *check.C) {
1.1       rillig   1495:        t := s.Init(c)
                   1496:
1.2       rillig   1497:        include, get := t.SetUpHierarchy()
                   1498:        include("including.mk",
                   1499:                "SUBDIR= ${WRKSRC}",
                   1500:                include("included.mk",
                   1501:                        "WRKSRC= ${WRKDIR}/${PKGBASE}"),
                   1502:                "WRKSRC= ${WRKDIR}/overwritten")
1.1       rillig   1503:
1.2       rillig   1504:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig   1505:
                   1506:        // Before pkglint 5.7.2 (2019-03-10), the above setup generated a warning:
                   1507:        //
                   1508:        // WARN: ~/included.mk:2: Variable WRKSRC is overwritten in including.mk:4.
                   1509:        //
                   1510:        // This warning is obviously wrong since the included file must never
                   1511:        // receive a warning. Of course this default definition may be overridden
                   1512:        // by the including file.
                   1513:        //
                   1514:        // The warning was generated because in including.mk:2 the variable WRKSRC
                   1515:        // was used for the first time. Back then, each variable had only a single
                   1516:        // include path. That include path marks where the variable is used and
                   1517:        // defined.
                   1518:        //
                   1519:        // The variable definition at included.mk didn't modify this include path.
                   1520:        // Therefore pkglint wrongly assumed that this variable was only ever
                   1521:        // accessed in including.mk and issued a warning.
                   1522:        //
                   1523:        // To fix this, the RedundantScope now remembers every access to the
                   1524:        // variable, and the redundancy warnings are only issued in cases where
                   1525:        // either all variable accesses are in files including the current file,
                   1526:        // or all variable accesses are in files included by the current file.
                   1527:        t.CheckOutputEmpty()
                   1528: }
                   1529:
                   1530: func (s *Suite) Test_RedundantScope_handleVarassign__conditional(c *check.C) {
                   1531:        t := s.Init(c)
                   1532:
                   1533:        mklines := t.NewMkLines("filename.mk",
1.2       rillig   1534:                "VAR=    value",
1.1       rillig   1535:                ".if 1",
1.2       rillig   1536:                "VAR=    conditional",
1.1       rillig   1537:                ".endif")
                   1538:
1.2       rillig   1539:        scope := NewRedundantScope()
                   1540:        scope.Check(mklines)
                   1541:        writeLocations := scope.get("VAR").vari.WriteLocations()
1.1       rillig   1542:
1.6       rillig   1543:        t.CheckDeepEquals(
1.2       rillig   1544:                writeLocations,
1.5       rillig   1545:                []*MkLine{mklines.mklines[0], mklines.mklines[2]})
1.2       rillig   1546: }
                   1547:
                   1548: // Ensures that commented variables do not influence the redundancy check.
1.7       rillig   1549: func (s *Suite) Test_RedundantScope_handleVarassign__commented_variable_assignment(c *check.C) {
1.2       rillig   1550:        t := s.Init(c)
                   1551:
                   1552:        include, get := t.SetUpHierarchy()
                   1553:        include("main.mk",
                   1554:                include("redundant.mk",
                   1555:                        "VAR=    value"),
                   1556:                include("doc.mk",
                   1557:                        "#OTHER= ${VAR}"),
                   1558:                "VAR=     value",
                   1559:                "OTHER=   value")
                   1560:
                   1561:        NewRedundantScope().Check(get("main.mk"))
                   1562:
                   1563:        t.CheckOutputLines(
                   1564:                "NOTE: main.mk:3: Definition of VAR is redundant because of redundant.mk:1.")
1.1       rillig   1565: }
                   1566:
1.10    ! rillig   1567: func (s *Suite) Test_RedundantScope_handleVarassign__assign_then_eval(c *check.C) {
        !          1568:        t := s.Init(c)
        !          1569:
        !          1570:        mklines := t.NewMkLines("mk/bsd.options.mk",
        !          1571:                "PKG_OPTIONS=\t# empty",
        !          1572:                "PKG_OPTIONS:=\t# empty")
        !          1573:
        !          1574:        scope := NewRedundantScope()
        !          1575:        scope.Check(mklines)
        !          1576:
        !          1577:        t.CheckOutputLines(
        !          1578:                "NOTE: mk/bsd.options.mk:2: " +
        !          1579:                        "Definition of PKG_OPTIONS is redundant because of line 1.")
        !          1580: }
        !          1581:
1.1       rillig   1582: func (s *Suite) Test_includePath_includes(c *check.C) {
                   1583:        t := s.Init(c)
                   1584:
1.9       rillig   1585:        path := func(locations ...CurrPath) includePath {
1.1       rillig   1586:                return includePath{locations}
                   1587:        }
                   1588:
                   1589:        var (
                   1590:                m   = path("Makefile")
                   1591:                mc  = path("Makefile", "Makefile.common")
                   1592:                mco = path("Makefile", "Makefile.common", "other.mk")
                   1593:                mo  = path("Makefile", "other.mk")
                   1594:        )
                   1595:
1.6       rillig   1596:        t.CheckEquals(m.includes(m), false)
1.1       rillig   1597:
1.6       rillig   1598:        t.CheckEquals(m.includes(mc), true)
                   1599:        t.CheckEquals(m.includes(mco), true)
                   1600:        t.CheckEquals(mc.includes(mco), true)
                   1601:
                   1602:        t.CheckEquals(mc.includes(m), false)
                   1603:        t.CheckEquals(mc.includes(mo), false)
                   1604:        t.CheckEquals(mo.includes(mc), false)
1.1       rillig   1605: }
                   1606:
                   1607: func (s *Suite) Test_includePath_equals(c *check.C) {
                   1608:        t := s.Init(c)
                   1609:
1.9       rillig   1610:        path := func(locations ...CurrPath) includePath {
1.1       rillig   1611:                return includePath{locations}
                   1612:        }
                   1613:
                   1614:        var (
                   1615:                m   = path("Makefile")
                   1616:                mc  = path("Makefile", "Makefile.common")
                   1617:                mco = path("Makefile", "Makefile.common", "other.mk")
                   1618:                mo  = path("Makefile", "other.mk")
                   1619:        )
                   1620:
1.6       rillig   1621:        t.CheckEquals(m.equals(m), true)
1.1       rillig   1622:
1.6       rillig   1623:        t.CheckEquals(m.equals(mc), false)
                   1624:        t.CheckEquals(m.equals(mco), false)
                   1625:        t.CheckEquals(mc.equals(mco), false)
                   1626:
                   1627:        t.CheckEquals(mc.equals(m), false)
                   1628:        t.CheckEquals(mc.equals(mo), false)
                   1629:        t.CheckEquals(mo.equals(mc), false)
1.1       rillig   1630: }

CVSweb <webmaster@jp.NetBSD.org>