diff --git a/Makefile.docker b/Makefile.docker
index ae927995c3f7cacc0d2e424a173fcd78dd4f1f2e..0db5936461ee91f76b75b09ed46a13def51f96ec 100644
--- a/Makefile.docker
+++ b/Makefile.docker
@@ -5,6 +5,8 @@ export DOCKER_FLAGS ?= --rm
 export DOCKER_MAKECMDGOALS_POSSIBLE = \
   all \
   buildtest \
+  scan-build \
+  scan-build-analyze \
   #
 export DOCKER_MAKECMDGOALS = $(filter $(MAKECMDGOALS),$(DOCKER_MAKECMDGOALS_POSSIBLE))
 
@@ -52,6 +54,8 @@ export DOCKER_ENV_VARS = \
   BUILDTEST_MCU_GROUP \
   BUILDTEST_VERBOSE \
   TOOLCHAIN \
+  SCANBUILD_OUTPUTDIR \
+  SCANBUILD_ARGS \
   #
 
 # Find which variables were set using the command line or the environment and
diff --git a/Makefile.include b/Makefile.include
index 8b253f64c811ef26822681ed702778240b352259..dcf05902b9ca36a060b8d6d9da26db80b808f66b 100644
--- a/Makefile.include
+++ b/Makefile.include
@@ -18,6 +18,9 @@ RIOTPROJECT := $(abspath $(RIOTPROJECT))
 # using abspath, strip etc.
 include $(RIOTBASE)/Makefile.docker
 
+# Static code analysis tools provided by LLVM
+include $(RIOTBASE)/Makefile.scan-build
+
 # Path to the current directory relative to the git root
 BUILDRELPATH ?= $(shell git rev-parse --show-prefix)
 
@@ -54,6 +57,12 @@ ifeq (, ${JENKINS_URL})
   endif
 endif
 
+ifeq ($(OS),Darwin)
+  OPEN   := open
+else
+  OPEN   := xdg-open
+endif
+
 ifeq ($(QUIET),1)
 	AD=@
 	MAKEFLAGS += --no-print-directory
diff --git a/Makefile.scan-build b/Makefile.scan-build
new file mode 100644
index 0000000000000000000000000000000000000000..5137d05a2ca90c672537e9243d69d93901ea9803
--- /dev/null
+++ b/Makefile.scan-build
@@ -0,0 +1,91 @@
+SCANBUILD_ENV_VARS := \
+  APPDIR \
+  AR \
+  ARFLAGS \
+  AS \
+  ASFLAGS \
+  BINDIR \
+  BINDIRBASE \
+  BOARD \
+  BUILDRELPATH \
+  CC \
+  CFLAGS \
+  CPPMIX \
+  CXX \
+  CXXEXFLAGS \
+  CXXUWFLAGS \
+  ELFFILE \
+  HEXFILE \
+  HOME \
+  LINK \
+  LINKFLAGPREFIX \
+  LINKFLAGS \
+  OBJCOPY \
+  OFLAGS \
+  PATH \
+  PREFIX \
+  QUIET \
+  RIOT_VERSION \
+  SIZE \
+  TOOLCHAIN \
+  UNDEF \
+  USER \
+  #
+
+SCANBUILD_ARGS ?= \
+  -analyze-headers \
+  --use-cc=$(CC) \
+  --use-c++=$(CXX) \
+  -analyzer-config stable-report-filename=true \
+  #
+
+export SCANBUILD_OUTPUTDIR = $(CURDIR)/scan-build/
+
+# Find all variables given on the command line and recreate the command.
+CMDVARS := $(strip $(foreach varname, $(SCANBUILD_ENV_VARS), \
+  $(if $(filter command, $(origin $(varname))), \
+  '$(varname)=$(subst ','\'',$($(varname)))', \
+  )))
+ENVVARS := $(strip $(foreach varname, $(SCANBUILD_ENV_VARS), \
+  $(if $(filter environment, $(origin $(varname))), \
+  '$(varname)=$(subst ','\'',$($(varname)))', \
+  )))
+
+.PHONY: scan-build scan-build-analyze scan-build-view
+scan-build: scan-build-view scan-build-analyze
+scan-build-view: scan-build-analyze
+ifeq ($(BUILD_IN_DOCKER),1)
+scan-build-analyze: ..in-docker-container
+else # BUILD_IN_DOCKER
+scan-build-analyze: clean
+	@$(COLOR_ECHO) '$(COLOR_GREEN)Performing Clang static code analysis using toolchain "$(TOOLCHAIN)".$(COLOR_RESET)'
+# ccc-analyzer needs to be told the proper -target setting for best results,
+# otherwise false error reports about unknown register names etc will be produced.
+# These kinds of errors can be safely ignored as long as they only come from LLVM
+	@if [ "$${TOOLCHAIN}" != "llvm" -a "$${BOARD}" != "native" ]; then \
+	  $(COLOR_ECHO) '$(COLOR_YELLOW)Recommend using TOOLCHAIN=llvm for best results.$(COLOR_RESET)'; \
+	  $(COLOR_ECHO) '$(COLOR_YELLOW)Ignore any "error: unknown register name '\''rX'\'' in asm" messages.$(COLOR_RESET)'; \
+	fi
+	$(AD)mkdir -p '$(SCANBUILD_OUTPUTDIR)'
+	$(AD)env -i $(ENVVARS) \
+	    scan-build -o '$(SCANBUILD_OUTPUTDIR)' $(SCANBUILD_ARGS) \
+	      make -C $(CURDIR) all $(strip $(CMDVARS));
+endif # BUILD_IN_DOCKER
+
+ifeq (1,$(INSIDE_DOCKER))
+scan-build-view:
+	@
+else
+	@echo "Showing most recent report in your web browser..."
+	@REPORT_FILE="$$(find '$(SCANBUILD_OUTPUTDIR)' -maxdepth 2 -mindepth 2 \
+	            -type f -name 'index.html' 2>/dev/null | sort | tail -n 1)"; \
+	  if [ -n "$${REPORT_FILE}" ]; then \
+	    echo "$(OPEN) $${REPORT_FILE}"; \
+	    $(OPEN) "$${REPORT_FILE}"; \
+	  else \
+	    echo "No report found"; \
+	  fi
+endif
+
+# Reset the default goal.
+.DEFAULT_GOAL :=