[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.2

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.",
        !            28:                "WARN: file.mk:4: Variable VAR.evl is overwritten in line 10.")
        !            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.",
        !            55:                "WARN: file.mk:4: Variable VAR.evl is overwritten in line 10.")
        !            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.",
        !           110:                "WARN: file.mk:4: Variable VAR.evl is overwritten in line 10.")
        !           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.1       rillig    733: // FIXME: Continue the systematic redundancy tests.
                    734: //
                    735: // Tests where the variables are defined conditionally using .if, .else, .endif.
                    736: //
                    737: // Tests where the variables are defined in a .for loop that might not be
                    738: // evaluated at all.
                    739: //
                    740: // Tests where files are included conditionally and additionally have conditional
                    741: // sections, arbitrarily nested.
                    742: //
                    743: // Tests that show how to suppress the notes about redundant assignments
                    744: // and overwritten variables. The explanation must be helpful.
                    745: //
                    746: // Tests for dynamic variable assignments. For example BUILD_DIRS.NetBSD may
                    747: // be modified by any assignment of the form BUILD_DIRS.${var} or even ${var}.
                    748: // Without further analysis, pkglint cannot report redundancy warnings for any
                    749: // package that uses such variable assignments.
1.2     ! rillig    750: //
        !           751: // Tests for variables with modifiers, such as ${VAR:Uundef}, ${VAR:Mpattern},
        !           752: // ${command:sh}, ${command::=value}.
        !           753: //
        !           754: // A test that compares a package with the default values from mk/defaults/mk.conf.
        !           755: // A package doesn't need to override these defaults, and the redundancy check
        !           756: // should notify the package author of this redundancy.
1.1       rillig    757:
                    758: func (s *Suite) Test_RedundantScope__override_after_including(c *check.C) {
                    759:        t := s.Init(c)
                    760:
1.2     ! rillig    761:        include, get := t.SetUpHierarchy()
        !           762:        include("including.mk",
        !           763:                include("included.mk",
        !           764:                        "OVERRIDE=       previous value",
        !           765:                        "REDUNDANT=      redundant"),
        !           766:                "OVERRIDE=       overridden value",
        !           767:                "REDUNDANT=      redundant")
        !           768:
        !           769:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig    770:
                    771:        t.CheckOutputLines(
                    772:                "NOTE: including.mk:3: Definition of REDUNDANT is redundant because of included.mk:2.")
                    773: }
                    774:
                    775: func (s *Suite) Test_RedundantScope__redundant_assign_after_including(c *check.C) {
                    776:        t := s.Init(c)
                    777:
1.2     ! rillig    778:        include, get := t.SetUpHierarchy()
        !           779:        include("including.mk",
        !           780:                include("included.mk",
        !           781:                        "REDUNDANT=      redundant"),
        !           782:                "REDUNDANT=      redundant")
        !           783:
        !           784:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig    785:
                    786:        t.CheckOutputLines(
                    787:                "NOTE: including.mk:2: Definition of REDUNDANT is redundant because of included.mk:1.")
                    788: }
                    789:
                    790: func (s *Suite) Test_RedundantScope__override_in_Makefile_after_including(c *check.C) {
                    791:        t := s.Init(c)
                    792:
1.2     ! rillig    793:        include, get := t.SetUpHierarchy()
        !           794:        include("Makefile",
        !           795:                include("module.mk",
        !           796:                        "VAR=    value ${OTHER}",
        !           797:                        "VAR?=   value ${OTHER}",
        !           798:                        "VAR=    new value"),
        !           799:                "VAR=    the package may overwrite variables from other files")
1.1       rillig    800:
                    801:        // XXX: The warnings from here are not in the same order as the other warnings.
                    802:        // XXX: There may be some warnings for the same file separated by warnings for other files.
1.2     ! rillig    803:        NewRedundantScope().Check(get("Makefile"))
1.1       rillig    804:
                    805:        // No warning for VAR=... in Makefile since it makes sense to have common files
                    806:        // with default values for variables, overriding some of them in each package.
                    807:        t.CheckOutputLines(
                    808:                "NOTE: module.mk:2: Default assignment of VAR has no effect because of line 1.",
                    809:                "WARN: module.mk:2: Variable VAR is overwritten in line 3.")
                    810: }
                    811:
                    812: func (s *Suite) Test_RedundantScope__default_value_definitely_unused(c *check.C) {
                    813:        t := s.Init(c)
1.2     ! rillig    814:
1.1       rillig    815:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig    816:                "VAR=    value ${OTHER}",
        !           817:                "VAR?=   different value")
1.1       rillig    818:
                    819:        NewRedundantScope().Check(mklines)
                    820:
                    821:        // A default assignment after an unconditional assignment is redundant.
                    822:        // Even more so when the variable is not used between the two assignments.
                    823:        t.CheckOutputLines(
                    824:                "NOTE: module.mk:2: Default assignment of VAR has no effect because of line 1.")
                    825: }
                    826:
                    827: func (s *Suite) Test_RedundantScope__default_value_overridden(c *check.C) {
                    828:        t := s.Init(c)
1.2     ! rillig    829:
1.1       rillig    830:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig    831:                "VAR?=   default value",
        !           832:                "VAR=    overridden value")
1.1       rillig    833:
                    834:        NewRedundantScope().Check(mklines)
                    835:
                    836:        t.CheckOutputLines(
                    837:                "WARN: module.mk:1: Variable VAR is overwritten in line 2.")
                    838: }
                    839:
                    840: func (s *Suite) Test_RedundantScope__overwrite_same_value(c *check.C) {
                    841:        t := s.Init(c)
1.2     ! rillig    842:
1.1       rillig    843:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig    844:                "VAR=    value ${OTHER}",
        !           845:                "VAR=    value ${OTHER}")
1.1       rillig    846:
                    847:        NewRedundantScope().Check(mklines)
                    848:
                    849:        t.CheckOutputLines(
                    850:                "NOTE: module.mk:2: Definition of VAR is redundant because of line 1.")
                    851: }
                    852:
                    853: func (s *Suite) Test_RedundantScope__conditional_overwrite(c *check.C) {
                    854:        t := s.Init(c)
1.2     ! rillig    855:
1.1       rillig    856:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig    857:                "VAR=    default",
1.1       rillig    858:                ".if ${OPSYS} == NetBSD",
1.2     ! rillig    859:                "VAR=    opsys",
1.1       rillig    860:                ".endif")
                    861:
                    862:        NewRedundantScope().Check(mklines)
                    863:
                    864:        t.CheckOutputEmpty()
                    865: }
                    866:
                    867: func (s *Suite) Test_RedundantScope__overwrite_inside_conditional(c *check.C) {
                    868:        t := s.Init(c)
1.2     ! rillig    869:
1.1       rillig    870:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig    871:                "VAR=    generic",
1.1       rillig    872:                ".if ${OPSYS} == NetBSD",
1.2     ! rillig    873:                "VAR=    ignored",
        !           874:                "VAR=    overwritten",
1.1       rillig    875:                ".endif")
                    876:
                    877:        NewRedundantScope().Check(mklines)
                    878:
                    879:        // TODO: expected a warning "WARN: module.mk:4: line 3 is ignored"
                    880:        // Since line 3 and line 4 are in the same basic block, line 3 is definitely ignored.
                    881:        t.CheckOutputEmpty()
                    882: }
                    883:
                    884: func (s *Suite) Test_RedundantScope__conditionally_include(c *check.C) {
                    885:        t := s.Init(c)
1.2     ! rillig    886:
        !           887:        include, get := t.SetUpHierarchy()
        !           888:        include("module.mk",
        !           889:                "VAR=    generic",
1.1       rillig    890:                ".if ${OPSYS} == NetBSD",
1.2     ! rillig    891:                include("included.mk",
        !           892:                        "VAR=    ignored",
        !           893:                        "VAR=    overwritten"),
1.1       rillig    894:                ".endif")
                    895:
1.2     ! rillig    896:        NewRedundantScope().Check(get("module.mk"))
1.1       rillig    897:
                    898:        // TODO: expected a warning "WARN: module.mk:4: line 3 is ignored"
                    899:        //  Since line 3 and line 4 are in the same basic block, line 3 is definitely ignored.
                    900:        t.CheckOutputEmpty()
                    901: }
                    902:
                    903: func (s *Suite) Test_RedundantScope__conditional_default(c *check.C) {
                    904:        t := s.Init(c)
1.2     ! rillig    905:
1.1       rillig    906:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig    907:                "VAR=    default",
1.1       rillig    908:                ".if ${OPSYS} == NetBSD",
1.2     ! rillig    909:                "VAR?=   opsys",
1.1       rillig    910:                ".endif")
                    911:
                    912:        NewRedundantScope().Check(mklines)
                    913:
1.2     ! rillig    914:        // TODO: WARN: module.mk:3: The value \"opsys\" will never be assigned
        !           915:        //  to VAR because it is defined unconditionally in line 1.
1.1       rillig    916:        t.CheckOutputEmpty()
                    917: }
                    918:
                    919: // These warnings are precise and accurate since the value of VAR is not used between line 2 and 4.
                    920: func (s *Suite) Test_RedundantScope__overwrite_same_variable_different_value(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:                "OTHER=  value before",
        !           925:                "VAR=    value ${OTHER}",
        !           926:                "OTHER=  value after",
        !           927:                "VAR=    value ${OTHER}")
1.1       rillig    928:
                    929:        NewRedundantScope().Check(mklines)
                    930:
                    931:        // Strictly speaking, line 1 is redundant because OTHER is not evaluated
                    932:        // at load time and then immediately overwritten in line 3. If the operator
                    933:        // in line 2 were a := instead of a =, the situation would be clear.
                    934:        // Pkglint doesn't warn about the redundancy in line 1 because it prefers
                    935:        // to omit warnings instead of giving wrong advice.
                    936:        t.CheckOutputLines(
                    937:                "NOTE: module.mk:4: Definition of VAR is redundant because of line 2.")
                    938: }
                    939:
                    940: func (s *Suite) Test_RedundantScope__overwrite_different_value_used_between(c *check.C) {
                    941:        t := s.Init(c)
1.2     ! rillig    942:
1.1       rillig    943:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig    944:                "OTHER=          value before",
        !           945:                "VAR=            value ${OTHER}",
1.1       rillig    946:
                    947:                // VAR is used here at load time, therefore it must be defined at this point.
                    948:                // At this point, VAR uses the \"before\" value of OTHER.
1.2     ! rillig    949:                "RESULT1:=       ${VAR}",
1.1       rillig    950:
1.2     ! rillig    951:                "OTHER=          value after",
1.1       rillig    952:
                    953:                // VAR is used here again at load time, this time using the \"after\" value of OTHER.
1.2     ! rillig    954:                "RESULT2:=       ${VAR}",
1.1       rillig    955:
                    956:                // Still this definition is redundant.
1.2     ! rillig    957:                "VAR=            value ${OTHER}")
1.1       rillig    958:
                    959:        NewRedundantScope().Check(mklines)
                    960:
                    961:        // There is nothing redundant here. Each write is followed by a
                    962:        // corresponding read, except for the last one. That is ok though
                    963:        // because in pkgsrc the last action of a package is to include
                    964:        // bsd.pkg.mk, which reads almost all variables.
                    965:        t.CheckOutputEmpty()
                    966: }
                    967:
                    968: func (s *Suite) Test_RedundantScope__procedure_call_to_noop(c *check.C) {
                    969:        t := s.Init(c)
                    970:
                    971:        include, get := t.SetUpHierarchy()
                    972:        include("mk/pthread.buildlink3.mk",
                    973:                "CHECK_BUILTIN.pthread:= yes",
                    974:                include("pthread.builtin.mk",
                    975:                        "# Nothing happens here."),
                    976:                "CHECK_BUILTIN.pthread:= no")
                    977:
                    978:        NewRedundantScope().Check(get("mk/pthread.buildlink3.mk"))
                    979:
                    980:        t.CheckOutputLines(
                    981:                "WARN: mk/pthread.buildlink3.mk:1: Variable CHECK_BUILTIN.pthread is overwritten in line 3.")
                    982: }
                    983:
                    984: func (s *Suite) Test_RedundantScope__procedure_call_implemented(c *check.C) {
                    985:        t := s.Init(c)
                    986:
                    987:        include, get := t.SetUpHierarchy()
                    988:        include("mk/pthread.buildlink3.mk",
                    989:                "CHECK_BUILTIN.pthread:= yes",
                    990:                include("pthread.builtin.mk",
                    991:                        "CHECK_BUILTIN.pthread?= no",
                    992:                        ".if !empty(CHECK_BUILTIN.pthread:M[Nn][Oo])",
                    993:                        ".endif"),
                    994:                "CHECK_BUILTIN.pthread:= no")
                    995:
                    996:        NewRedundantScope().Check(get("mk/pthread.buildlink3.mk"))
                    997:
                    998:        // This test is a bit unrealistic. It wrongly assumes that all files from
                    999:        // an .include directive are actually included by pkglint.
                   1000:        //
                   1001:        // See Package.readMakefile/handleIncludeLine/skip.
                   1002:        t.CheckOutputEmpty()
                   1003: }
                   1004:
                   1005: func (s *Suite) Test_RedundantScope__procedure_call_implemented_package(c *check.C) {
                   1006:        t := s.Init(c)
                   1007:
                   1008:        t.SetUpPkgsrc()
                   1009:        t.SetUpPackage("devel/gettext-lib")
                   1010:        t.SetUpPackage("x11/Xaos",
                   1011:                ".include \"../../devel/gettext-lib/buildlink3.mk\"")
                   1012:        t.CreateFileLines("devel/gettext-lib/builtin.mk",
                   1013:                MkRcsID,
                   1014:                "",
                   1015:                ".include \"../../mk/bsd.fast.prefs.mk\"",
                   1016:                "",
1.2     ! rillig   1017:                "CHECK_BUILTIN.gettext?= no",
1.1       rillig   1018:                ".if !empty(CHECK_BUILTIN.gettext:M[nN][oO])",
                   1019:                ".endif")
                   1020:        t.CreateFileLines("devel/gettext-lib/buildlink3.mk",
                   1021:                MkRcsID,
1.2     ! rillig   1022:                "CHECK_BUILTIN.gettext:= yes",
1.1       rillig   1023:                ".include \"builtin.mk\"",
1.2     ! rillig   1024:                "CHECK_BUILTIN.gettext:= no")
1.1       rillig   1025:        G.Pkgsrc.LoadInfrastructure()
                   1026:
                   1027:        // Checking x11/Xaos instead of devel/gettext-lib avoids warnings
                   1028:        // about the minimal buildlink3.mk file.
                   1029:        G.Check(t.File("x11/Xaos"))
                   1030:
                   1031:        // There is nothing redundant here.
                   1032:        // Up to March 2019, pkglint didn't pass the correct pathnames to Package.included,
                   1033:        // which triggered a wrong note here.
                   1034:        t.CheckOutputEmpty()
                   1035: }
                   1036:
                   1037: func (s *Suite) Test_RedundantScope__procedure_call_infrastructure(c *check.C) {
                   1038:        t := s.Init(c)
                   1039:
                   1040:        t.SetUpPackage("x11/alacarte",
                   1041:                ".include \"../../mk/pthread.buildlink3.mk\"")
                   1042:        t.CreateFileLines("mk/pthread.buildlink3.mk",
                   1043:                MkRcsID,
1.2     ! rillig   1044:                "CHECK_BUILTIN.gettext:= yes",
1.1       rillig   1045:                ".include \"pthread.builtin.mk\"",
1.2     ! rillig   1046:                "CHECK_BUILTIN.gettext:= no")
1.1       rillig   1047:        t.CreateFileLines("mk/pthread.builtin.mk",
                   1048:                MkRcsID,
1.2     ! rillig   1049:                "CHECK_BUILTIN.gettext?= no",
1.1       rillig   1050:                ".if !empty(CHECK_BUILTIN.gettext:M[nN][oO])",
                   1051:                ".endif")
                   1052:        G.Pkgsrc.LoadInfrastructure()
                   1053:
                   1054:        G.Check(t.File("x11/alacarte"))
                   1055:
                   1056:        // There is nothing redundant here.
                   1057:        //
                   1058:        // 1. pthread.buildlink3.mk sets the variable
                   1059:        // 2. pthread.builtin.mk assigns it a default value
                   1060:        //    (which is common practice)
                   1061:        // 3. pthread.builtin.mk then reads it
                   1062:        //    (which marks the next write as non-redundant)
                   1063:        // 4. pthread.buildlink3.mk sets the variable again
                   1064:        //    (this is considered neither overwriting nor redundant)
                   1065:        //
                   1066:        // Up to March 2019, pkglint complained:
                   1067:        //
                   1068:        // WARN: ~/mk/pthread.buildlink3.mk:2:
                   1069:        //     Variable CHECK_BUILTIN.gettext is overwritten in line 4.
                   1070:        //
                   1071:        // The cause for the warning is that when including files from the
                   1072:        // infrastructure, pkglint only includes the outermost level of files.
                   1073:        // If an infrastructure file includes another infrastructure file,
                   1074:        // pkglint skips that, for performance reasons.
                   1075:        //
                   1076:        // This optimization effectively made the .include for pthread.builtin.mk
                   1077:        // a no-op, therefore it was correct to issue a warning here.
                   1078:        //
                   1079:        // Since this warning is wrong, in March 2019 another special rule has
                   1080:        // been added to Package.readMakefile.handleIncludeLine.skip saying that
                   1081:        // including a buildlink3.mk file also includes the corresponding
                   1082:        // builtin.mk file.
                   1083:        t.CheckOutputEmpty()
                   1084: }
                   1085:
                   1086: func (s *Suite) Test_RedundantScope__shell_and_eval(c *check.C) {
                   1087:        t := s.Init(c)
1.2     ! rillig   1088:
1.1       rillig   1089:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig   1090:                "VAR:=    value ${OTHER}",
        !          1091:                "VAR!=    value ${OTHER}")
1.1       rillig   1092:
                   1093:        NewRedundantScope().Check(mklines)
                   1094:
                   1095:        // As of November 2018, pkglint doesn't check redundancies that involve the := or != operators.
                   1096:        //
                   1097:        // What happens here is:
                   1098:        //
                   1099:        // Line 1 evaluates OTHER at load time.
                   1100:        // Line 1 assigns its value to VAR.
                   1101:        // Line 2 evaluates OTHER at load time.
                   1102:        // Line 2 passes its value through the shell and assigns the result to VAR.
                   1103:        //
                   1104:        // Since VAR is defined in line 1, not used afterwards and overwritten in line 2, it is redundant.
                   1105:        // Well, not quite, because evaluating ${OTHER} might have side-effects from :sh or ::= modifiers,
                   1106:        // but these are so rare that they are frowned upon and are not considered by pkglint.
                   1107:        //
                   1108:        // Expected result:
                   1109:        // WARN: module.mk:2: Previous definition of VAR in line 1 is unused.
                   1110:
                   1111:        t.CheckOutputEmpty()
                   1112: }
                   1113:
                   1114: func (s *Suite) Test_RedundantScope__shell_and_eval_literal(c *check.C) {
                   1115:        t := s.Init(c)
1.2     ! rillig   1116:
1.1       rillig   1117:        mklines := t.NewMkLines("module.mk",
1.2     ! rillig   1118:                "VAR:=    value",
        !          1119:                "VAR!=    value")
1.1       rillig   1120:
                   1121:        NewRedundantScope().Check(mklines)
                   1122:
                   1123:        // Even when := is used with a literal value (which is usually
                   1124:        // only done for procedure calls), the shell evaluation can have
                   1125:        // so many different side effects that pkglint cannot reliably
                   1126:        // help in this situation.
                   1127:        //
                   1128:        // TODO: Why not? The evaluation in line 1 is trivial to analyze.
                   1129:        t.CheckOutputEmpty()
                   1130: }
                   1131:
                   1132: func (s *Suite) Test_RedundantScope__included_OPSYS_variable(c *check.C) {
                   1133:        t := s.Init(c)
                   1134:
                   1135:        t.SetUpPackage("category/package",
                   1136:                ".include \"../../category/dependency/buildlink3.mk\"",
1.2     ! rillig   1137:                "CONFIGURE_ARGS+=        one",
        !          1138:                "CONFIGURE_ARGS=         two",
        !          1139:                "CONFIGURE_ARGS+=        three")
1.1       rillig   1140:        t.SetUpPackage("category/dependency")
                   1141:        t.CreateFileDummyBuildlink3("category/dependency/buildlink3.mk")
                   1142:        t.CreateFileLines("category/dependency/builtin.mk",
                   1143:                MkRcsID,
1.2     ! rillig   1144:                "CONFIGURE_ARGS.Darwin+= darwin")
1.1       rillig   1145:
                   1146:        G.Check(t.File("category/package"))
                   1147:
                   1148:        t.CheckOutputLines(
                   1149:                "WARN: ~/category/package/Makefile:21: Variable CONFIGURE_ARGS is overwritten in line 22.")
                   1150: }
                   1151:
                   1152: func (s *Suite) Test_RedundantScope__if_then_else(c *check.C) {
                   1153:        t := s.Init(c)
                   1154:
1.2     ! rillig   1155:        mklines := t.NewMkLines("if-then-else.mk",
1.1       rillig   1156:                ".if exists(${FILE})",
1.2     ! rillig   1157:                "OS=     NetBSD",
1.1       rillig   1158:                ".else",
1.2     ! rillig   1159:                "OS=     OTHER",
1.1       rillig   1160:                ".endif")
                   1161:
                   1162:        NewRedundantScope().Check(mklines)
                   1163:
                   1164:        // These two definitions are of course not redundant since they happen in
                   1165:        // different branches of the same .if statement.
                   1166:        t.CheckOutputEmpty()
                   1167: }
                   1168:
                   1169: func (s *Suite) Test_RedundantScope__if_then_else_without_variable(c *check.C) {
                   1170:        t := s.Init(c)
                   1171:
1.2     ! rillig   1172:        mklines := t.NewMkLines("if-then-else.mk",
1.1       rillig   1173:                ".if exists(/nonexistent)",
1.2     ! rillig   1174:                "IT=     exists",
1.1       rillig   1175:                ".else",
1.2     ! rillig   1176:                "IT=     doesn't exist",
1.1       rillig   1177:                ".endif")
                   1178:
                   1179:        NewRedundantScope().Check(mklines)
                   1180:
                   1181:        // These two definitions are of course not redundant since they happen in
                   1182:        // different branches of the same .if statement.
                   1183:        // Even though the .if condition does not refer to any variables,
                   1184:        // this still means that the variable assignments are conditional.
                   1185:        t.CheckOutputEmpty()
                   1186: }
                   1187:
                   1188: func (s *Suite) Test_RedundantScope__append_then_default(c *check.C) {
                   1189:        t := s.Init(c)
                   1190:
1.2     ! rillig   1191:        mklines := t.NewMkLines("append-then-default.mk",
        !          1192:                "VAR+=   value",
        !          1193:                "VAR?=   value")
1.1       rillig   1194:
                   1195:        NewRedundantScope().Check(mklines)
                   1196:
                   1197:        t.CheckOutputLines(
1.2     ! rillig   1198:                "NOTE: append-then-default.mk:2: Default assignment of VAR has no effect because of line 1.")
1.1       rillig   1199: }
                   1200:
                   1201: func (s *Suite) Test_RedundantScope__assign_then_default_in_same_file(c *check.C) {
                   1202:        t := s.Init(c)
                   1203:
1.2     ! rillig   1204:        mklines := t.NewMkLines("assign-then-default.mk",
        !          1205:                "VAR=    value",
        !          1206:                "VAR?=   value")
1.1       rillig   1207:
                   1208:        NewRedundantScope().Check(mklines)
                   1209:
                   1210:        t.CheckOutputLines(
1.2     ! rillig   1211:                "NOTE: assign-then-default.mk:2: " +
        !          1212:                        "Default assignment of VAR has no effect because of line 1.")
1.1       rillig   1213: }
                   1214:
                   1215: func (s *Suite) Test_RedundantScope__eval_then_eval(c *check.C) {
                   1216:        t := s.Init(c)
                   1217:
1.2     ! rillig   1218:        mklines := t.NewMkLines("filename.mk",
        !          1219:                "VAR:=   value",
        !          1220:                "VAR:=   value",
        !          1221:                "VAR:=   other")
1.1       rillig   1222:
                   1223:        NewRedundantScope().Check(mklines)
                   1224:
                   1225:        t.CheckOutputLines(
1.2     ! rillig   1226:                "WARN: filename.mk:1: Variable VAR is overwritten in line 2.",
        !          1227:                "WARN: filename.mk:2: Variable VAR is overwritten in line 3.")
1.1       rillig   1228: }
                   1229:
                   1230: func (s *Suite) Test_RedundantScope__shell_then_assign(c *check.C) {
                   1231:        t := s.Init(c)
                   1232:
1.2     ! rillig   1233:        mklines := t.NewMkLines("filename.mk",
        !          1234:                "VAR!=   echo echo",
        !          1235:                "VAR=    echo echo")
1.1       rillig   1236:
                   1237:        NewRedundantScope().Check(mklines)
                   1238:
                   1239:        // Although the two variable assignments look very similar, they do
                   1240:        // something entirely different. The first executes the echo command,
                   1241:        // and the second just assigns a string. Therefore the actual variable
                   1242:        // values are different, and the second assignment is not redundant.
                   1243:        // It assigns a different value. Nevertheless, the shell command is
                   1244:        // redundant and can be removed since its result is never used.
                   1245:        t.CheckOutputLines(
1.2     ! rillig   1246:                "WARN: filename.mk:1: Variable VAR is overwritten in line 2.")
1.1       rillig   1247: }
                   1248:
                   1249: func (s *Suite) Test_RedundantScope__shell_then_read_then_assign(c *check.C) {
                   1250:        t := s.Init(c)
                   1251:
                   1252:        mklines := t.SetUpFileMkLines("filename.mk",
1.2     ! rillig   1253:                "VAR!=           echo echo",
        !          1254:                "OUTPUT:=        ${VAR}",
        !          1255:                "VAR=            echo echo")
1.1       rillig   1256:
                   1257:        NewRedundantScope().Check(mklines)
                   1258:
                   1259:        // No warning since the value is used in-between.
                   1260:        t.CheckOutputEmpty()
                   1261: }
                   1262:
                   1263: func (s *Suite) Test_RedundantScope__assign_then_default_in_included_file(c *check.C) {
                   1264:        t := s.Init(c)
                   1265:
1.2     ! rillig   1266:        include, get := t.SetUpHierarchy()
        !          1267:        include("assign-then-default.mk",
        !          1268:                "VAR=    value",
        !          1269:                include("included.mk",
        !          1270:                        "VAR?=    value"))
1.1       rillig   1271:
1.2     ! rillig   1272:        NewRedundantScope().Check(get("assign-then-default.mk"))
1.1       rillig   1273:
1.2     ! rillig   1274:        // If assign-then-default.mk:1 were deleted, VAR would still have the same value.
1.1       rillig   1275:        t.CheckOutputLines(
1.2     ! rillig   1276:                "NOTE: assign-then-default.mk:1: Definition of VAR is redundant because of included.mk:1.")
1.1       rillig   1277: }
                   1278:
                   1279: func (s *Suite) Test_RedundantScope__conditionally_included_file(c *check.C) {
                   1280:        t := s.Init(c)
                   1281:
1.2     ! rillig   1282:        include, get := t.SetUpHierarchy()
        !          1283:        include("including.mk",
        !          1284:                "VAR=    value",
1.1       rillig   1285:                ".if ${COND}",
1.2     ! rillig   1286:                include("included.mk",
        !          1287:                        "VAR?=   value"),
1.1       rillig   1288:                ".endif")
                   1289:
1.2     ! rillig   1290:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig   1291:
                   1292:        // The assignment in including.mk:2 is only redundant if included.mk is actually included.
                   1293:        // Therefore both included.mk:2 nor including.mk:2 are relevant.
                   1294:        t.CheckOutputEmpty()
                   1295: }
                   1296:
                   1297: func (s *Suite) Test_RedundantScope__procedure_parameters(c *check.C) {
                   1298:        t := s.Init(c)
                   1299:
1.2     ! rillig   1300:        // TODO: make Tester.SetUpHierarchy accept a file multiple times.
1.1       rillig   1301:        t.CreateFileLines("mk/pkg-build-options.mk",
1.2     ! rillig   1302:                "USED:=  ${pkgbase}")
1.1       rillig   1303:        t.CreateFileLines("including.mk",
1.2     ! rillig   1304:                "pkgbase= package1",
1.1       rillig   1305:                ".include \"mk/pkg-build-options.mk\"",
                   1306:                "",
1.2     ! rillig   1307:                "pkgbase= package2",
1.1       rillig   1308:                ".include \"mk/pkg-build-options.mk\"",
                   1309:                "",
1.2     ! rillig   1310:                "pkgbase= package3",
1.1       rillig   1311:                ".include \"mk/pkg-build-options.mk\"")
                   1312:        mklines := t.LoadMkInclude("including.mk")
                   1313:
                   1314:        NewRedundantScope().Check(mklines)
                   1315:
                   1316:        // This variable is not overwritten since it is used in-between
                   1317:        // by the included file.
                   1318:        t.CheckOutputEmpty()
                   1319: }
                   1320:
                   1321: // Branch coverage for info.vari.Constant(). The other tests typically
                   1322: // make a variable non-constant by adding conditional assignments between
                   1323: // .if/.endif. But there are other ways. The output of shell commands is
                   1324: // unpredictable for pkglint (as of March 2019), therefore it treats these
                   1325: // variables as non-constant.
                   1326: func (s *Suite) Test_RedundantScope_handleVarassign__shell_followed_by_default(c *check.C) {
                   1327:        t := s.Init(c)
                   1328:
                   1329:        include, get := t.SetUpHierarchy()
                   1330:        include("including.mk",
1.2     ! rillig   1331:                "VAR!=   echo 'hello, world'",
1.1       rillig   1332:                include("included.mk",
1.2     ! rillig   1333:                        "VAR?=   hello world"))
1.1       rillig   1334:
                   1335:        NewRedundantScope().Check(get("including.mk"))
                   1336:
                   1337:        // If pkglint should ever learn to interpret simple shell commands, there
                   1338:        // should be a warning for including.mk:2 that the shell command generates
                   1339:        // the default value.
                   1340:        t.CheckOutputEmpty()
                   1341: }
                   1342:
                   1343: func (s *Suite) Test_RedundantScope__overwrite_definition_from_included_file(c *check.C) {
                   1344:        t := s.Init(c)
                   1345:
1.2     ! rillig   1346:        include, get := t.SetUpHierarchy()
        !          1347:        include("including.mk",
        !          1348:                "SUBDIR= ${WRKSRC}",
        !          1349:                include("included.mk",
        !          1350:                        "WRKSRC= ${WRKDIR}/${PKGBASE}"),
        !          1351:                "WRKSRC= ${WRKDIR}/overwritten")
1.1       rillig   1352:
1.2     ! rillig   1353:        NewRedundantScope().Check(get("including.mk"))
1.1       rillig   1354:
                   1355:        // Before pkglint 5.7.2 (2019-03-10), the above setup generated a warning:
                   1356:        //
                   1357:        // WARN: ~/included.mk:2: Variable WRKSRC is overwritten in including.mk:4.
                   1358:        //
                   1359:        // This warning is obviously wrong since the included file must never
                   1360:        // receive a warning. Of course this default definition may be overridden
                   1361:        // by the including file.
                   1362:        //
                   1363:        // The warning was generated because in including.mk:2 the variable WRKSRC
                   1364:        // was used for the first time. Back then, each variable had only a single
                   1365:        // include path. That include path marks where the variable is used and
                   1366:        // defined.
                   1367:        //
                   1368:        // The variable definition at included.mk didn't modify this include path.
                   1369:        // Therefore pkglint wrongly assumed that this variable was only ever
                   1370:        // accessed in including.mk and issued a warning.
                   1371:        //
                   1372:        // To fix this, the RedundantScope now remembers every access to the
                   1373:        // variable, and the redundancy warnings are only issued in cases where
                   1374:        // either all variable accesses are in files including the current file,
                   1375:        // or all variable accesses are in files included by the current file.
                   1376:        t.CheckOutputEmpty()
                   1377: }
                   1378:
                   1379: func (s *Suite) Test_RedundantScope_handleVarassign__conditional(c *check.C) {
                   1380:        t := s.Init(c)
                   1381:
                   1382:        mklines := t.NewMkLines("filename.mk",
1.2     ! rillig   1383:                "VAR=    value",
1.1       rillig   1384:                ".if 1",
1.2     ! rillig   1385:                "VAR=    conditional",
1.1       rillig   1386:                ".endif")
                   1387:
1.2     ! rillig   1388:        scope := NewRedundantScope()
        !          1389:        scope.Check(mklines)
        !          1390:        writeLocations := scope.get("VAR").vari.WriteLocations()
1.1       rillig   1391:
                   1392:        t.Check(
1.2     ! rillig   1393:                writeLocations,
1.1       rillig   1394:                deepEquals,
1.2     ! rillig   1395:                []MkLine{mklines.mklines[0], mklines.mklines[2]})
        !          1396: }
        !          1397:
        !          1398: // Ensures that commented variables do not influence the redundancy check.
        !          1399: func (s *Suite) Test_RedundantScope__commented_variable_assignment(c *check.C) {
        !          1400:        t := s.Init(c)
        !          1401:
        !          1402:        include, get := t.SetUpHierarchy()
        !          1403:        include("main.mk",
        !          1404:                include("redundant.mk",
        !          1405:                        "VAR=    value"),
        !          1406:                include("doc.mk",
        !          1407:                        "#OTHER= ${VAR}"),
        !          1408:                "VAR=     value",
        !          1409:                "OTHER=   value")
        !          1410:
        !          1411:        NewRedundantScope().Check(get("main.mk"))
        !          1412:
        !          1413:        t.CheckOutputLines(
        !          1414:                "NOTE: main.mk:3: Definition of VAR is redundant because of redundant.mk:1.")
1.1       rillig   1415: }
                   1416:
                   1417: func (s *Suite) Test_includePath_includes(c *check.C) {
                   1418:        t := s.Init(c)
                   1419:
                   1420:        path := func(locations ...string) includePath {
                   1421:                return includePath{locations}
                   1422:        }
                   1423:
                   1424:        var (
                   1425:                m   = path("Makefile")
                   1426:                mc  = path("Makefile", "Makefile.common")
                   1427:                mco = path("Makefile", "Makefile.common", "other.mk")
                   1428:                mo  = path("Makefile", "other.mk")
                   1429:        )
                   1430:
                   1431:        t.Check(m.includes(m), equals, false)
                   1432:
                   1433:        t.Check(m.includes(mc), equals, true)
                   1434:        t.Check(m.includes(mco), equals, true)
                   1435:        t.Check(mc.includes(mco), equals, true)
                   1436:
                   1437:        t.Check(mc.includes(m), equals, false)
                   1438:        t.Check(mc.includes(mo), equals, false)
                   1439:        t.Check(mo.includes(mc), equals, false)
                   1440: }
                   1441:
                   1442: func (s *Suite) Test_includePath_equals(c *check.C) {
                   1443:        t := s.Init(c)
                   1444:
                   1445:        path := func(locations ...string) includePath {
                   1446:                return includePath{locations}
                   1447:        }
                   1448:
                   1449:        var (
                   1450:                m   = path("Makefile")
                   1451:                mc  = path("Makefile", "Makefile.common")
                   1452:                mco = path("Makefile", "Makefile.common", "other.mk")
                   1453:                mo  = path("Makefile", "other.mk")
                   1454:        )
                   1455:
                   1456:        t.Check(m.equals(m), equals, true)
                   1457:
                   1458:        t.Check(m.equals(mc), equals, false)
                   1459:        t.Check(m.equals(mco), equals, false)
                   1460:        t.Check(mc.equals(mco), equals, false)
                   1461:
                   1462:        t.Check(mc.equals(m), equals, false)
                   1463:        t.Check(mc.equals(mo), equals, false)
                   1464:        t.Check(mo.equals(mc), equals, false)
                   1465: }

CVSweb <webmaster@jp.NetBSD.org>