* static (not necessarily explicit) typing
* no dynamic metaprogramming (static OK)
* no "eval"
* no first-class functions (second-class OK)
* no prototype-based OOP (class-based OK)
* no mutable variables (lexical shadowing OK)
* no mutable values, or very strict aliasing rules
* no unbounded recursion
* no dynamically defined structures
Of course you can perform useful static analysis with only some of these guidelines met. e.g. Erlang's Dialyzer does pretty well with dynamic typing, first-class functions, and unbounded recursion, because these features generally aren't abused in Erlang. (Though this took a hit recently due to the recent introduction of the `maps` feature, which was designed in such a way as to encourage violating that last guideline, despite proposals for a similar feature which would not have violated it.)
Surprisingly, C also meets all but two of these guidelines, and, although it is an egregious violator of those both, it is somewhat amenable to static analysis (see Coverity).
JavaScript, on the other hand, is notoriously difficult to statically analyze, since it not only permits code to violate all the above guidelines, but it's common for code to violate all of them.