diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py
index c811f9040ebc2c57072be66e858b4ceb0279251e..299c56481e49607f91abb1a99bada704780c6210 100644
--- a/lib/spack/spack/test/packages.py
+++ b/lib/spack/spack/test/packages.py
@@ -98,6 +98,10 @@ def test_all_same_but_archive_hash(self):
         assert spec1.package.content_hash(content=content1) != \
             spec2.package.content_hash(content=content2)
 
+    def test_parse_dynamic_function_call(self):
+        spec = Spec("hash-test4").concretized()
+        spec.package.content_hash()
+
     # Below tests target direct imports of spack packages from the
     # spack.pkg namespace
     def test_import_package(self):
diff --git a/lib/spack/spack/util/package_hash.py b/lib/spack/spack/util/package_hash.py
index f689aa9710fa369566bc265b9d90816610296d00..adea1a498b0b7db55f8f180264746b27f21b27d2 100644
--- a/lib/spack/spack/util/package_hash.py
+++ b/lib/spack/spack/util/package_hash.py
@@ -41,8 +41,23 @@ def __init__(self, spec):
         self.spec = spec
 
     def is_directive(self, node):
+        """Check to determine if the node is a valid directive
+
+        Directives are assumed to be represented in the AST as a named function
+        call expression.  This means that they will NOT be represented by a
+        named function call within a function call expression (e.g., as
+        callbacks are sometimes represented).
+
+        Args:
+            node (AST): the AST node being checked
+
+        Returns:
+            (bool): ``True`` if the node represents a known directive,
+                ``False`` otherwise
+        """
         return (isinstance(node, ast.Expr) and
                 node.value and isinstance(node.value, ast.Call) and
+                isinstance(node.value.func, ast.Name) and
                 node.value.func.id in spack.directives.__all__)
 
     def is_spack_attr(self, node):
diff --git a/var/spack/repos/builtin.mock/packages/hash-test4/package.py b/var/spack/repos/builtin.mock/packages/hash-test4/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b7f4d40c0d446153b7243e63ffdd047353065b2
--- /dev/null
+++ b/var/spack/repos/builtin.mock/packages/hash-test4/package.py
@@ -0,0 +1,27 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack import *
+
+
+class HashTest4(Package):
+    """This package isn't compared with others, but it contains constructs
+       that package hashing logic has tripped over in the past.
+    """
+
+    homepage = "http://www.hashtest4.org"
+    url = "http://www.hashtest1.org/downloads/hashtest4-1.1.tar.bz2"
+
+    version('1.1', 'a' * 32)
+
+    def install(self, spec, prefix):
+        pass
+
+    @staticmethod
+    def examine_prefix(pkg):
+        pass
+
+    run_after('install')(
+        examine_prefix)