...

Source file src/github.com/bazelbuild/buildtools/warn/warn_control_flow_test.go

Documentation: github.com/bazelbuild/buildtools/warn

     1  /*
     2  Copyright 2020 Google LLC
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package warn
    18  
    19  import "testing"
    20  
    21  func TestMissingReturnValueWarning(t *testing.T) {
    22  	// empty return
    23  	checkFindings(t, "return-value", `
    24  def foo():
    25    if x:
    26      return x
    27    else:
    28      return
    29  `, []string{
    30  		`:5: Some but not all execution paths of "foo" return a value.`,
    31  	}, scopeEverywhere)
    32  
    33  	// empty return; implicit return in the end
    34  	checkFindings(t, "return-value", `
    35  def bar():
    36    if x:
    37      pass
    38    elif y:
    39      return y
    40    else:
    41      for z in t:
    42        return
    43  `, []string{
    44  		`:1: Some but not all execution paths of "bar" return a value.
    45  The function may terminate by an implicit return in the end.`,
    46  		`:8: Some but not all execution paths of "bar" return a value.`,
    47  	}, scopeEverywhere)
    48  
    49  	// implicit return in the end
    50  	checkFindings(t, "return-value", `
    51  def foo():
    52    if x:
    53      return x
    54    else:
    55      bar()
    56  `, []string{
    57  		`:1: Some but not all execution paths of "foo" return a value.
    58  The function may terminate by an implicit return in the end.`,
    59  	}, scopeEverywhere)
    60  
    61  	// implicit return in the end
    62  	checkFindings(t, "return-value", `
    63  def bar():
    64    if x:
    65      return x
    66    elif y:
    67      return y
    68    else:
    69      foo
    70      if z:
    71        return z
    72  
    73    if foo:
    74       return not foo
    75  `, []string{
    76  		`:1: Some but not all execution paths of "bar" return a value.
    77  The function may terminate by an implicit return in the end.`,
    78  	}, scopeEverywhere)
    79  
    80  	// only returned values and fail() statements, ok
    81  	checkFindings(t, "return-value", `
    82  def bar():
    83    if x:
    84      return x
    85    elif y:
    86      return y
    87    else:
    88      foo
    89      if z:
    90        return z
    91  
    92    if foo:
    93       return not foo
    94    else:
    95       fail("unreachable")
    96  `, []string{}, scopeEverywhere)
    97  
    98  	// implicit return in the end because fail() is not a statement
    99  	checkFindings(t, "return-value", `
   100  def bar():
   101    if x:
   102      return x
   103    elif y:
   104      return y
   105    else:
   106      foo
   107      if z:
   108        return z
   109  
   110    if foo:
   111       return not foo
   112    else:
   113       foo() or fail("unreachable")
   114  `, []string{
   115  		`:1: Some but not all execution paths of "bar" return a value.
   116  The function may terminate by an implicit return in the end.`,
   117  	}, scopeEverywhere)
   118  
   119  	// only empty returns, ok
   120  	checkFindings(t, "return-value", `
   121  def bar():
   122    if x:
   123      x()
   124    elif y:
   125      return
   126    else:
   127      foo
   128      if z:
   129        fail()
   130  
   131    if foo:
   132       return
   133  `, []string{}, scopeEverywhere)
   134  
   135  	// no returns, ok
   136  	checkFindings(t, "return-value", `
   137  def foobar():
   138    pass
   139  `, []string{}, scopeEverywhere)
   140  
   141  	// only fails, ok
   142  	checkFindings(t, "return-value", `
   143  def foobar():
   144    if foo:
   145      fail()
   146  `, []string{}, scopeEverywhere)
   147  
   148  	// nested functions, no errors
   149  	checkFindings(t, "return-value", `
   150  def foo():
   151    def bar():
   152      pass
   153  
   154    return bar
   155  `, []string{}, scopeEverywhere)
   156  
   157  	// nested functions, missing return value in the outer function
   158  	checkFindings(t, "return-value", `
   159  def foo():
   160    def bar():
   161      pass
   162  
   163    if bar():
   164      return 42
   165  `, []string{
   166  		`:1: Some but not all execution paths of "foo" return a value.
   167  The function may terminate by an implicit return in the end.`,
   168  	}, scopeEverywhere)
   169  
   170  	// nested functions, missing return value in the inner function
   171  	checkFindings(t, "return-value", `
   172  def foo():
   173    def bar():
   174      if something:
   175        return something
   176  
   177    if bar():
   178      return 42
   179    return 43
   180  `, []string{
   181  		`:2: Some but not all execution paths of "bar" return a value.
   182  The function may terminate by an implicit return in the end.`,
   183  	}, scopeEverywhere)
   184  
   185  	// nested functions, missing return value in both
   186  	checkFindings(t, "return-value", `
   187  def foo():
   188    def bar():
   189      if something:
   190        return something
   191  
   192    if bar():
   193      return 42
   194  `, []string{
   195  		`:1: Some but not all execution paths of "foo" return a value.
   196  The function may terminate by an implicit return in the end.`,
   197  		`:2: Some but not all execution paths of "bar" return a value.
   198  The function may terminate by an implicit return in the end.`,
   199  	}, scopeEverywhere)
   200  }
   201  
   202  func TestUnreachableStatementWarning(t *testing.T) {
   203  	// after return
   204  	checkFindings(t, "unreachable", `
   205  def foo():
   206    return
   207    bar()
   208    baz()
   209  `, []string{
   210  		`:3: The statement is unreachable.`,
   211  	}, scopeEverywhere)
   212  
   213  	// two returns
   214  	checkFindings(t, "unreachable", `
   215  def foo():
   216    return 1
   217    return 2
   218  `, []string{
   219  		`:3: The statement is unreachable.`,
   220  	}, scopeEverywhere)
   221  
   222  	// after fail()
   223  	checkFindings(t, "unreachable", `
   224  def foo():
   225    fail("die")
   226    bar()
   227    baz()
   228  `, []string{
   229  		`:3: The statement is unreachable.`,
   230  	}, scopeEverywhere)
   231  
   232  	// after break and continue
   233  	checkFindings(t, "unreachable", `
   234  def foo():
   235    for x in y:
   236      if x:
   237        break
   238        bar()  # unreachable
   239      if y:
   240        continue
   241        bar()  # unreachable
   242  
   243  def bar():
   244    for x in y:
   245      if x:
   246        break
   247      elif y:
   248        continue
   249      else:
   250        return x
   251  
   252      foo()  # unreachable
   253    foobar()  # potentially reachable
   254  `, []string{
   255  		`:5: The statement is unreachable.`,
   256  		`:8: The statement is unreachable.`,
   257  		`:19: The statement is unreachable.`,
   258  	}, scopeEverywhere)
   259  
   260  	// ok
   261  	checkFindings(t, "unreachable", `
   262  def foo():
   263    if x:
   264      return
   265    bar()
   266  `, []string{}, scopeEverywhere)
   267  
   268  	// ok
   269  	checkFindings(t, "unreachable", `
   270  def foo():
   271    x() or fail("maybe")
   272    bar()
   273  `, []string{}, scopeEverywhere)
   274  
   275  	// unreacheable statement inside a nested function
   276  	checkFindings(t, "unreachable", `
   277  def foo():
   278    def bar():
   279      fail("die")
   280      baz()
   281  `, []string{
   282  		`:4: The statement is unreachable.`,
   283  	}, scopeEverywhere)
   284  
   285  }
   286  
   287  func TestNoEffect(t *testing.T) {
   288  	checkFindings(t, "no-effect", `
   289  """Docstring."""
   290  def bar():
   291      """Other Docstring"""
   292      fct()
   293      pass
   294      return 2
   295  
   296  [f() for i in rang(3)] # top-level comprehension is okay
   297  `,
   298  		[]string{},
   299  		scopeEverywhere)
   300  
   301  	checkFindings(t, "no-effect", `
   302  def foo():
   303      [fct() for i in range(3)]
   304  	`,
   305  		[]string{":2: Expression result is not used. Use a for-loop instead"},
   306  		scopeEverywhere)
   307  
   308  	checkFindings(t, "no-effect", `None`,
   309  		[]string{":1: Expression result is not used."},
   310  		scopeEverywhere)
   311  
   312  	checkFindings(t, "no-effect", `
   313  foo             # 1
   314  foo()
   315  
   316  def bar():
   317      [1, 2]      # 5
   318      if True:
   319        "string"  # 7
   320  `,
   321  		[]string{":1:", ":5:", ":7:"},
   322  		scopeEverywhere)
   323  
   324  	checkFindings(t, "no-effect", `
   325  # A comment
   326  
   327  """A docstring"""
   328  
   329  # Another comment
   330  
   331  """Not a docstring"""
   332  
   333  def bar():
   334      """A docstring"""
   335      foo
   336      """ Not a docstring"""
   337      return foo
   338  `,
   339  		[]string{
   340  			":7: Expression result is not used. Docstrings should be the first statements of a file or a function (they may follow comment lines).",
   341  			":11: Expression result is not used.",
   342  			":12: Expression result is not used. Docstrings should be the first statements of a file or a function (they may follow comment lines).",
   343  		}, scopeEverywhere)
   344  
   345  	checkFindings(t, "no-effect", `
   346  foo == bar
   347  foo = bar
   348  a + b
   349  c // d
   350  -e
   351  foo != bar
   352  
   353  foo += bar
   354  bar -= bar
   355  
   356  `,
   357  		[]string{":1:", ":3:", ":4:", ":5:", ":6:"},
   358  		scopeEverywhere)
   359  
   360  	checkFindings(t, "no-effect", `
   361  def foo():
   362    """Doc."""
   363    def bar():
   364      """Doc."""
   365      foo == bar
   366  `,
   367  		[]string{":5:"},
   368  		scopeEverywhere)
   369  }
   370  
   371  func TestWarnUnusedVariable(t *testing.T) {
   372  	checkFindings(t, "unused-variable", `
   373  load(":f.bzl", "x")
   374  x = "unused"
   375  y = "also unused"
   376  z = "name"
   377  t = "unused by design"  # @unused
   378  _foo, _bar = pair  #@unused
   379  cc_library(name = z)
   380  
   381  def f():
   382    pass
   383  
   384  def g():
   385    pass
   386  
   387  g() + 3
   388  `,
   389  		[]string{":2: Variable \"x\" is unused.",
   390  			":3: Variable \"y\" is unused.",
   391  			":9: Function \"f\" is unused."},
   392  		scopeDeclarative)
   393  
   394  	checkFindings(t, "unused-variable", `
   395  a = 1
   396  b = 2
   397  c = 3
   398  d = (a if b else c)  # only d is unused
   399  `,
   400  		[]string{":4: Variable \"d\" is unused."},
   401  		scopeDeclarative)
   402  
   403  	checkFindings(t, "unused-variable", `
   404  _a = 1
   405  _a += 2
   406  _b = 3
   407  print(_b)
   408  
   409  def _f(): pass
   410  def _g(): pass
   411  _g()
   412  `,
   413  		[]string{
   414  			":1: Variable \"_a\" is unused.",
   415  			":6: Function \"_f\" is unused.",
   416  		},
   417  		scopeEverywhere)
   418  
   419  	checkFindings(t, "unused-variable", `
   420  a = 1
   421  
   422  def foo(
   423      x,
   424      y = 0,
   425      z = 1):
   426    b = 2
   427    c = 3
   428    d = (a if b else c)  # only d is unused
   429    e = 7
   430    f = 8  # @unused
   431    # @unused
   432    g = 9
   433  
   434    return e + z
   435  
   436  foo()
   437  `,
   438  		[]string{
   439  			":4: Variable \"x\" is unused.",
   440  			":5: Variable \"y\" is unused.",
   441  			":9: Variable \"d\" is unused.",
   442  		},
   443  		scopeEverywhere)
   444  
   445  	checkFindings(t, "unused-variable", `
   446  a = 1
   447  
   448  def foo(a):
   449    b = 2
   450    return a
   451  
   452  def foo():
   453    pass
   454  
   455  def bar(c, cc):
   456    d = 3
   457    print(c)
   458  
   459    def baz():
   460      foo()
   461      d = 4
   462      return a
   463  
   464  bar()
   465  `,
   466  		[]string{
   467  			":4: Variable \"b\" is unused.",
   468  			":10: Variable \"cc\" is unused.",
   469  			":11: Variable \"d\" is unused.",
   470  			":14: Function \"baz\" is unused.",
   471  			":16: Variable \"d\" is unused.",
   472  		},
   473  		scopeEverywhere)
   474  
   475  	checkFindings(t, "unused-variable", `
   476  def foo():
   477    a = 1
   478    b = 2
   479    c = 3
   480  
   481    def bar(
   482        x = a + baz(c = 4),
   483        y = b):
   484      pass
   485  
   486  foo()
   487  `,
   488  		[]string{
   489  			":4: Variable \"c\" is unused.",
   490  			":6: Function \"bar\" is unused.",
   491  			":7: Variable \"x\" is unused.",
   492  			":8: Variable \"y\" is unused.",
   493  		},
   494  		scopeEverywhere)
   495  
   496  	checkFindings(t, "unused-variable", `
   497  def foo():
   498    a = 1
   499    b = 2
   500    c = [x for a in aa if a % b for x in a]
   501    return c
   502  
   503  foo()
   504  `,
   505  		[]string{
   506  			":2: Variable \"a\" is unused.",
   507  		},
   508  		scopeEverywhere)
   509  
   510  	checkFindings(t, "unused-variable", `
   511  def foo():
   512    a = 1
   513    b = 2
   514    c = [
   515      a + b
   516      for a in [b for b in bb if b]
   517      if a
   518    ]
   519    return c
   520  
   521  foo()
   522  `,
   523  		[]string{
   524  			":2: Variable \"a\" is unused.",
   525  		},
   526  		scopeEverywhere)
   527  
   528  	checkFindings(t, "unused-variable", `
   529  def foo():
   530    a = 1
   531    b = 2
   532  
   533    def bar(*args):
   534      def baz(**kwargs):
   535        def foobar(*a,
   536                   **kw):
   537          return b
   538        return foobar(**kwargs)
   539      return baz(*args)
   540    return bar()
   541  
   542  foo()
   543  `,
   544  		[]string{
   545  			":2: Variable \"a\" is unused.",
   546  			":7: Variable \"a\" is unused.",
   547  			":8: Variable \"kw\" is unused.",
   548  		},
   549  		scopeEverywhere)
   550  
   551  	checkFindings(t, "unused-variable", `
   552  def foo():
   553    a = 1
   554    b = 2
   555    c = 3
   556    d = 4
   557    e, f = 5, 6
   558  
   559    for x, yy in xx:
   560      for (y, z, _, _t) in yy:
   561        print(a + y)
   562  
   563    if bar:
   564      print(c)
   565    elif baz:
   566      print(d)
   567    else:
   568      print(e)
   569  
   570  foo()
   571  `,
   572  		[]string{
   573  			":3: Variable \"b\" is unused.",
   574  			":6: Variable \"f\" is unused.",
   575  			":8: Variable \"x\" is unused.",
   576  			":9: Variable \"z\" is unused.",
   577  		},
   578  		scopeEverywhere)
   579  
   580  	checkFindings(t, "unused-variable", `
   581  def foo():
   582  
   583    # @unused
   584    def bar():
   585      pass
   586  
   587    def baz():
   588      pass
   589  
   590  foo()
   591  `,
   592  		[]string{
   593  			":7: Function \"baz\" is unused.",
   594  		},
   595  		scopeEverywhere)
   596  
   597  	checkFindings(t, "unused-variable", `
   598  def foo(my_iterable, arg, _some_unused_argument, _also_unused = None, *_args, **_kwargs):
   599  
   600    a, b, _c = 1, 2, 3  # ok to not use _c
   601    print(a)
   602  
   603    _d, _e = 4, 5  # all are underscored
   604    print(_d)
   605  
   606    for f, g, _h, _ in my_iterable:  # ok to not use any underscored
   607      print(f)
   608  
   609    for _i, (_j, _k) in another_iterable:  # ok to not use any of them
   610      pass
   611  
   612    [1 for (_y, _z) in bar]
   613  
   614  foo()
   615  `,
   616  		[]string{
   617  			":1: Variable \"arg\" is unused.",
   618  			":3: Variable \"b\" is unused.",
   619  			":6: Variable \"_e\" is unused.",
   620  			":9: Variable \"g\" is unused.",
   621  		},
   622  		scopeEverywhere)
   623  
   624  	checkFindings(t, "unused-variable", `
   625  def foo(
   626      x,
   627      _y,
   628      z,  # @unused
   629      t = 42,  #@unused
   630      *args,  # @unused
   631      **kwargs,  ### also @unused
   632  ):
   633    pass
   634  
   635  foo()
   636  `,
   637  		[]string{
   638  			":2: Variable \"x\" is unused.",
   639  		},
   640  		scopeEverywhere)
   641  
   642  	checkFindings(t, "unused-variable", `
   643  def foo(
   644      name,
   645      x):
   646    pass
   647  
   648  
   649  def bar(
   650      name = "",
   651      y = 3):
   652    pass
   653  
   654  
   655  foo()
   656  bar()
   657  `,
   658  		[]string{
   659  			":3: Variable \"x\" is unused.",
   660  			":9: Variable \"y\" is unused.",
   661  		},
   662  		scopeEverywhere)
   663  }
   664  
   665  func TestRedefinedVariable(t *testing.T) {
   666  	checkFindings(t, "redefined-variable", `
   667  x = "old_value"
   668  x = "new_value"
   669  x[1] = "new"
   670  cc_library(name = x)`,
   671  		[]string{":2: Variable \"x\" has already been defined."},
   672  		scopeEverywhere)
   673  
   674  	checkFindings(t, "redefined-variable", `
   675  x = "a"
   676  
   677  def foo():
   678    x = "b"
   679    y = "c"
   680    y = "d"
   681  
   682  def bar():
   683    x = "e"
   684    y = "f"
   685    y = "g"`,
   686  		[]string{},
   687  		scopeEverywhere)
   688  
   689  	checkFindings(t, "redefined-variable", `
   690  x = [1, 2, 3]
   691  y = [a for a in b]
   692  z = list()
   693  n = 43
   694  
   695  x += something()
   696  y += something()
   697  z += something()
   698  n += something()
   699  x -= something()`,
   700  		[]string{
   701  			":9: Variable \"n\" has already been defined.",
   702  			":10: Variable \"x\" has already been defined.",
   703  		},
   704  		scopeEverywhere)
   705  
   706  	checkFindings(t, "redefined-variable", `
   707  x = [1, 2, 3]
   708  y = [a for a in b]
   709  z = list()
   710  
   711  a = something()
   712  b = something()
   713  c = something()
   714  d = something()
   715  e = something()
   716  
   717  a += x
   718  b += y
   719  c += z
   720  d += [42]
   721  e += foo`,
   722  		[]string{
   723  			":15: Variable \"e\" has already been defined.",
   724  		},
   725  		scopeEverywhere)
   726  }
   727  
   728  func TestWarnUnusedLoad(t *testing.T) {
   729  	checkFindingsAndFix(t, "load", `
   730  load(":f.bzl", "s1", "s2")
   731  load(":bar.bzl", "s1")
   732  foo(name = s1)`, `
   733  load(":f.bzl", "s1")
   734  load(":bar.bzl", "s1")
   735  foo(name = s1)`,
   736  		[]string{
   737  			":1: Loaded symbol \"s2\" is unused.",
   738  			":2: A different symbol \"s1\" has already been loaded on line 1.",
   739  		},
   740  		scopeEverywhere)
   741  
   742  	checkFindingsAndFix(t, "load", `
   743  load("foo", "b", "a", "c")
   744  load("foo", "a", "d", "e")
   745  
   746  z = a + b + d`, `
   747  load("foo", "a", "b")
   748  load("foo", "d")
   749  
   750  z = a + b + d`,
   751  		[]string{
   752  			":1: Loaded symbol \"c\" is unused.",
   753  			":2: Symbol \"a\" has already been loaded on line 1.",
   754  			":2: Loaded symbol \"e\" is unused.",
   755  		},
   756  		scopeEverywhere)
   757  
   758  	checkFindingsAndFix(t, "load", `
   759  load("foo", "a")
   760  a(1)
   761  load("bar", "a")
   762  a(2)
   763  load("bar", a = "a")
   764  a(3)
   765  load("bar", a = "b")
   766  a(4)
   767  load("foo", "a")
   768  a(5)
   769  load("foo", "a")
   770  a(6)
   771  load("foo", a = "a")
   772  a(7)`, `
   773  load("foo", "a")
   774  a(1)
   775  load("bar", "a")
   776  a(2)
   777  
   778  a(3)
   779  load("bar", a = "b")
   780  a(4)
   781  load("foo", "a")
   782  a(5)
   783  
   784  a(6)
   785  
   786  a(7)`,
   787  		[]string{
   788  			":3: A different symbol \"a\" has already been loaded on line 1.",
   789  			":5: Symbol \"a\" has already been loaded on line 3.",
   790  			":7: A different symbol \"a\" has already been loaded on line 5.",
   791  			":9: A different symbol \"a\" has already been loaded on line 7.",
   792  			":11: Symbol \"a\" has already been loaded on line 9.",
   793  			":13: Symbol \"a\" has already been loaded on line 11.",
   794  		},
   795  		scopeEverywhere)
   796  
   797  	checkFindingsAndFix(t, "load", `
   798  load(
   799    ":f.bzl",
   800     "s1",
   801     "s2",  # @unused (s2)
   802  )
   803  
   804  # @unused - both s3 and s4
   805  load(
   806    ":f.bzl",
   807     "s3",
   808     "s4",
   809  )`, `
   810  load(
   811    ":f.bzl",
   812     "s2",  # @unused (s2)
   813  )
   814  
   815  # @unused - both s3 and s4
   816  load(
   817    ":f.bzl",
   818     "s3",
   819     "s4",
   820  )`,
   821  		[]string{":3: Loaded symbol \"s1\" is unused."},
   822  		scopeEverywhere)
   823  
   824  	checkFindingsAndFix(t, "load", `
   825  load(":f.bzl", "x")
   826  x = "unused"`, `
   827  x = "unused"`,
   828  		[]string{":1: Loaded symbol \"x\" is unused."},
   829  		scopeEverywhere)
   830  
   831  	checkFindings(t, "load", `
   832  load(
   833    ":f.bzl",
   834     "s1",
   835  )
   836  
   837  def test(x: s1):
   838    pass
   839  `,
   840  		[]string{},
   841  		scopeEverywhere)
   842  	checkFindings(t, "load", `
   843  load(
   844    ":f.bzl",
   845    "s1",
   846    "s2",
   847  )
   848  
   849  def test(x: s1) -> List[s2]:
   850    pass
   851  `,
   852  		[]string{},
   853  		scopeEverywhere)
   854  	checkFindingsAndFix(t, "load", `
   855  load(
   856    ":f.bzl",
   857    "s1",
   858    "s2",
   859  )
   860  
   861  load(
   862    ":s.bzl",
   863    "s3",
   864  )
   865  
   866  def test(x: s1) -> List[s2]:
   867    pass
   868  `, `
   869  load(
   870    ":f.bzl",
   871    "s1",
   872    "s2",
   873  )
   874  
   875  def test(x: s1) -> List[s2]:
   876    pass
   877  `,
   878  		[]string{
   879  			":9: Loaded symbol \"s3\" is unused.",
   880  		},
   881  		scopeEverywhere)
   882  }
   883  
   884  func TestUninitializedVariable(t *testing.T) {
   885  	checkFindings(t, "uninitialized", `
   886  def foo(x):
   887    if bar:
   888      x = 1
   889      y = 2
   890  
   891    bar = True
   892    print(x + y)
   893  `,
   894  		[]string{
   895  			":2: Variable \"bar\" may not have been initialized.",
   896  			":7: Variable \"y\" may not have been initialized.",
   897  		},
   898  		scopeEverywhere)
   899  
   900  	checkFindings(t, "uninitialized", `
   901  def foo(x):
   902    for t in s:
   903      x = 1
   904      y = 2
   905  
   906    print(x + y)
   907  `,
   908  		[]string{
   909  			":6: Variable \"y\" may not have been initialized.",
   910  		},
   911  		scopeEverywhere)
   912  
   913  	checkFindings(t, "uninitialized", `
   914  def foo():
   915    if bar:
   916      x = 1
   917      y = 2
   918    else:
   919      if foobar:
   920        x = 3
   921        y = 4
   922      else:
   923        x = 5
   924  
   925    print(x + y)
   926  `,
   927  		[]string{
   928  			":12: Variable \"y\" may not have been initialized.",
   929  		},
   930  		scopeEverywhere)
   931  
   932  	checkFindings(t, "uninitialized", `
   933  def foo(x):
   934    if bar:
   935      t = 1
   936    else:
   937      for t in maybe_empty:  
   938        pass
   939  
   940    print(t)
   941  `,
   942  		[]string{
   943  			":8: Variable \"t\" may not have been initialized.",
   944  		},
   945  		scopeEverywhere)
   946  
   947  	checkFindings(t, "uninitialized", `
   948  def foo(x):
   949    if bar:
   950      t = 1
   951    else:
   952      for y in maybe_empty:  
   953        return
   954  
   955    print(t)
   956  `,
   957  		[]string{
   958  			":8: Variable \"t\" may not have been initialized.",
   959  		},
   960  		scopeEverywhere)
   961  
   962  	checkFindings(t, "uninitialized", `
   963  def foo(x):
   964    if bar:
   965      for t in [2, 3]:
   966        pass
   967  
   968    print(t)
   969  `,
   970  		[]string{
   971  			":6: Variable \"t\" may not have been initialized.",
   972  		},
   973  		scopeEverywhere)
   974  
   975  	checkFindings(t, "uninitialized", `
   976  def foo(x):
   977    print(t)  # maybe global or loaded
   978  `,
   979  		[]string{},
   980  		scopeEverywhere)
   981  
   982  	checkFindings(t, "uninitialized", `
   983  def foo(x):
   984    if bar:
   985      y = 1
   986  
   987    print(y)
   988    x, y = y, x
   989    print(y)
   990  `,
   991  		[]string{
   992  			":5: Variable \"y\" may not have been initialized.",
   993  			":6: Variable \"y\" may not have been initialized.",
   994  		},
   995  		scopeEverywhere)
   996  
   997  	checkFindings(t, "uninitialized", `
   998  def foo():
   999    if a:
  1000      x = 1
  1001      y = 1
  1002      z = 1
  1003    elif b:
  1004      x = 2
  1005      z = 2
  1006      t = 2
  1007    else:
  1008      x = 3
  1009      y = 3
  1010      t = 3
  1011  
  1012    print(x + y + z + t)
  1013  `,
  1014  		[]string{
  1015  			":15: Variable \"y\" may not have been initialized.",
  1016  			":15: Variable \"z\" may not have been initialized.",
  1017  			":15: Variable \"t\" may not have been initialized.",
  1018  		},
  1019  		scopeEverywhere)
  1020  
  1021  	checkFindings(t, "uninitialized", `
  1022  def foo(y):
  1023    if y < 0:
  1024      x = -1
  1025    elif y > 0:
  1026      x = 1
  1027    else:
  1028      fail()
  1029  
  1030    print(x)
  1031  `,
  1032  		[]string{},
  1033  		scopeEverywhere)
  1034  
  1035  	checkFindings(t, "uninitialized", `
  1036  def foo(y):
  1037    if y < 0:
  1038      x = -1
  1039    elif y > 0:
  1040      x = 1
  1041    else:
  1042      if z:
  1043        fail("z")
  1044      else:
  1045        fail("not z")
  1046  
  1047    print(x)
  1048  `,
  1049  		[]string{},
  1050  		scopeEverywhere)
  1051  
  1052  	checkFindings(t, "uninitialized", `
  1053  def foo(y):
  1054    if y < 0:
  1055      return
  1056    elif y > 0:
  1057      x = 1
  1058    else:
  1059      return x  # not initialized
  1060  
  1061    print(x)
  1062  `,
  1063  		[]string{
  1064  			":7: Variable \"x\" may not have been initialized.",
  1065  		},
  1066  		scopeEverywhere)
  1067  
  1068  	checkFindings(t, "uninitialized", `
  1069  def foo(y):
  1070    if y < 0:
  1071      return
  1072    elif y > 0:
  1073      x = 1
  1074    else:
  1075      pass
  1076  
  1077    print(x)  # not initialized
  1078  `,
  1079  		[]string{
  1080  			":9: Variable \"x\" may not have been initialized.",
  1081  		},
  1082  		scopeEverywhere)
  1083  
  1084  	checkFindings(t, "uninitialized", `
  1085  def foo():
  1086    for x in y:
  1087      print(x)
  1088      print(x.attr)
  1089  
  1090    print(x)
  1091    print(x.attr)
  1092  `,
  1093  		[]string{
  1094  			":6: Variable \"x\" may not have been initialized.",
  1095  			":7: Variable \"x\" may not have been initialized.",
  1096  		},
  1097  		scopeEverywhere)
  1098  
  1099  	checkFindings(t, "uninitialized", `
  1100  def foo():
  1101    for x in y:
  1102      a = x
  1103      print(a)
  1104  
  1105    print(a)
  1106  `,
  1107  		[]string{
  1108  			":6: Variable \"a\" may not have been initialized.",
  1109  		},
  1110  		scopeEverywhere)
  1111  
  1112  	checkFindings(t, "uninitialized", `
  1113  def f():
  1114      if foo:
  1115          x = foo
  1116  
  1117      f(x = y)
  1118  `,
  1119  		[]string{},
  1120  		scopeEverywhere)
  1121  
  1122  	checkFindings(t, "uninitialized", `
  1123  def f():
  1124      if foo:
  1125          x = foo
  1126  
  1127      f(x + y)
  1128  `,
  1129  		[]string{
  1130  			":5: Variable \"x\" may not have been initialized.",
  1131  		},
  1132  		scopeEverywhere)
  1133  
  1134  	checkFindings(t, "uninitialized", `
  1135  def f():
  1136      if foo:
  1137          x = foo
  1138  
  1139      x, y = 1, x
  1140  `,
  1141  		[]string{
  1142  			":5: Variable \"x\" may not have been initialized.",
  1143  		},
  1144  		scopeEverywhere)
  1145  
  1146  	checkFindings(t, "uninitialized", `
  1147  def f():
  1148      if foo:
  1149          x = foo
  1150  
  1151      x, y = 1, 2
  1152  `,
  1153  		[]string{},
  1154  		scopeEverywhere)
  1155  
  1156  	checkFindings(t, "uninitialized", `
  1157  def f(y):
  1158      return [x for x in y if x]
  1159  
  1160      x = 1
  1161  `,
  1162  		[]string{},
  1163  		scopeEverywhere)
  1164  
  1165  	checkFindings(t, "uninitialized", `
  1166  def f():
  1167      if foo:
  1168          f(x = foo)
  1169      else:
  1170          x = 3
  1171  
  1172      print(x)
  1173  `,
  1174  		[]string{
  1175  			":7: Variable \"x\" may not have been initialized.",
  1176  		},
  1177  		scopeEverywhere)
  1178  
  1179  	checkFindings(t, "uninitialized", `
  1180  def foo(x):
  1181    for y in x:
  1182      if foo:
  1183        break
  1184      elif bar:
  1185        continue
  1186      elif baz:
  1187        return
  1188      else:
  1189        z = 3
  1190      print(z)
  1191  `,
  1192  		[]string{},
  1193  		scopeEverywhere)
  1194  
  1195  	checkFindings(t, "uninitialized", `
  1196  def foo(x: int, y: int = 2):
  1197    if bar:
  1198      x = 1
  1199      y = 2
  1200      z = 3
  1201  
  1202    print(x + y + z)
  1203  `,
  1204  		[]string{
  1205  			":7: Variable \"z\" may not have been initialized.",
  1206  		},
  1207  		scopeEverywhere)
  1208  
  1209  	checkFindings(t, "uninitialized", `
  1210  def foo(x: int, y: int = 2):
  1211    def bar(y=x):
  1212      if baz:
  1213        x = 1
  1214        y = 2
  1215        z = 3
  1216  
  1217      print(x + y + z)
  1218  
  1219    if something:
  1220      x = bar()
  1221  
  1222    return x
  1223  `,
  1224  		[]string{
  1225  			":8: Variable \"x\" may not have been initialized.",
  1226  			":8: Variable \"z\" may not have been initialized.",
  1227  		},
  1228  		scopeEverywhere)
  1229  
  1230  	checkFindings(t, "uninitialized", `
  1231  def foo(x: int, y: int = 2):
  1232    if bar:
  1233      y, z, t = 2, 3, 4
  1234      w, s = 5, 6
  1235      r = 7
  1236  
  1237    [t for t in range(5)]
  1238    [a for a in range(z + y)]
  1239    {b: c + s for b, c in [
  1240      d * 2 for d in range(t)
  1241      if d != baz(r=w)
  1242    ]}
  1243  `,
  1244  		[]string{
  1245  			":8: Variable \"z\" may not have been initialized.",
  1246  			":9: Variable \"s\" may not have been initialized.",
  1247  			":10: Variable \"t\" may not have been initialized.",
  1248  			":11: Variable \"w\" may not have been initialized.",
  1249  		},
  1250  		scopeEverywhere)
  1251  
  1252  	checkFindings(t, "uninitialized", `
  1253  def foo():
  1254    x = 1
  1255    for y, z in t:
  1256        print(y, z)
  1257  
  1258    def bar(x, y, s = z):
  1259      pass
  1260  `,
  1261  		[]string{
  1262  			":6: Variable \"z\" may not have been initialized.",
  1263  		},
  1264  		scopeEverywhere)
  1265  
  1266  	checkFindings(t, "uninitialized", `
  1267  def foo():
  1268    for bar in baz:
  1269      pass
  1270  
  1271    y = [baz.get(bar) for bar in bars]
  1272    x = lambda bar: baz.get(bar)
  1273  `,
  1274  		[]string{},
  1275  		scopeEverywhere)
  1276  
  1277  	checkFindings(t, "uninitialized", `
  1278  def foo():
  1279    def bar(x):
  1280      print(x)
  1281  
  1282    for x, y in z:
  1283      bar(x)
  1284  `,
  1285  		[]string{},
  1286  		scopeEverywhere)
  1287  
  1288  	checkFindings(t, "uninitialized", `
  1289  def foo():
  1290    [x, y] = [1, 2]
  1291    x = 3
  1292    print(x)
  1293  `,
  1294  		[]string{},
  1295  		scopeEverywhere)
  1296  }
  1297  

View as plain text