Bug 767563 - Add a clang static checker, part 1: add the plugin shell. r=glandium
authorJoshua Cranmer <Pidgeot18@gmail.com>
Sat, 23 Mar 2013 21:12:25 -0500
changeset 126404 cf75954e488fa602bf19de0b44a710066d0a5c5d
parent 126403 0ed97a9289b6f331be3658a30c2f315fe2d5f529
child 126405 9dfc8698edd08ea77c193b4ffe69ec8421983559
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersglandium
bugs767563
milestone22.0a1
Bug 767563 - Add a clang static checker, part 1: add the plugin shell. r=glandium
build/clang-plugin/Makefile.in
build/clang-plugin/clang-plugin.cpp
build/clang-plugin/configure
config/static-checking-config.mk
configure.in
js/src/config/static-checking-config.mk
js/src/configure.in
moz.build
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/Makefile.in
@@ -0,0 +1,39 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+CXX      := @CXX@
+CXXFLAGS := @CXXFLAGS@
+LDFLAGS  := @LDFLAGS@
+VPATH		 := @srcdir@
+
+# Helper for end
+NULL :=
+
+CPPSRCS := \
+	clang-plugin.cpp \
+	$(NULL)
+
+TESTSRCS := \
+	$(NULL)
+
+OBJS := $(patsubst %.cpp,%.o,$(CPPSRCS))
+TESTS := $(patsubst %.cpp,test-%,$(TESTSRCS))
+
+PLUGIN := libclang-plugin.so
+
+all: $(PLUGIN) $(TESTS)
+
+$(OBJS): %.o: %.cpp Makefile
+	$(CXX) -o $@ -c $(CXXFLAGS) $<
+
+$(PLUGIN): $(OBJS)
+	rm -f $@
+	$(CXX) -shared -o $@ $(CXXFLAGS) $(LDFLAGS) $(OBJS)
+
+TESTFLAGS := -fsyntax-only -Xclang -verify \
+	-Xclang -load -Xclang $(CURDIR)/$(PLUGIN) \
+	-Xclang -add-plugin -Xclang moz-check
+
+$(TESTS): test-%: tests/%.cpp $(PLUGIN)
+	$(CXX) $(TESTFLAGS) $<
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Sema/Sema.h"
+
+#define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR)
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
+  DiagnosticsEngine &Diag;
+  const CompilerInstance &CI;
+public:
+  MozChecker(const CompilerInstance &CI) : Diag(CI.getDiagnostics()), CI(CI) {}
+  virtual void HandleTranslationUnit(ASTContext &ctx) {
+    TraverseDecl(ctx.getTranslationUnitDecl());
+  }
+};
+
+class MozCheckAction : public PluginASTAction {
+public:
+  ASTConsumer *CreateASTConsumer(CompilerInstance &CI, StringRef fileName) {
+    return new MozChecker(CI);
+  }
+
+  bool ParseArgs(const CompilerInstance &CI,
+                 const std::vector<std::string> &args) {
+    return true;
+  }
+};
+}
+
+static FrontendPluginRegistry::Add<MozCheckAction>
+X("moz-check", "check moz action");
new file mode 100755
--- /dev/null
+++ b/build/clang-plugin/configure
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+# Default srcdir to this directory
+srcdir=
+
+for option; do
+  case "$option" in
+  -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  case "$option" in
+  --srcdir=*) srcdir="$optarg";;
+  esac
+done
+
+if test -z "$CXX"; then
+  CXX=`which clang++`
+fi
+
+echo -n "checking for llvm-config... "
+
+if test -z "$LLVMCONFIG"; then
+  LLVMCONFIG=`which llvm-config`
+fi
+
+if test -z "$LLVMCONFIG"; then
+  LLVMCONFIG=`dirname $CXX`/llvm-config
+fi
+
+if test ! -x "$LLVMCONFIG"; then
+  echo "configure: error: Cannot find an llvm-config binary for building a clang plugin" 1>&2
+  exit 1
+fi
+
+echo "$LLVMCONFIG"
+
+LLVMCXXFLAGS=`$LLVMCONFIG --cxxflags`
+LLVMLDFLAGS=`$LLVMCONFIG --ldflags`
+CXXFLAGS="$CXXFLAGS $LLVMCXXFLAGS -fno-rtti -fno-exceptions"
+LDFLAGS="$LDFLAGS $LLVMLDFLAGS"
+
+cat $srcdir/Makefile.in | sed \
+  -e "s%@CXX@%$CXX%" \
+  -e "s%@CXXFLAGS@%$CXXFLAGS%" \
+  -e "s%@LDFLAGS@%$LDFLAGS%" \
+  -e "s%@srcdir@%$srcdir%" \
+  > Makefile
--- a/config/static-checking-config.mk
+++ b/config/static-checking-config.mk
@@ -31,8 +31,14 @@ DEHYDRA_ARGS = \
   $(DEHYDRA_ARG_PREFIX)treehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(TREEHYDRA_MODULES))) \
   $(NULL)
 
 DEHYDRA_FLAGS = -fplugin=$(DEHYDRA_PATH) $(DEHYDRA_ARGS)
 
 ifdef DEHYDRA_PATH
 OS_CXXFLAGS += $(DEHYDRA_FLAGS)
 endif
+
+ifdef ENABLE_CLANG_PLUGIN
+CLANG_PLUGIN := $(DEPTH)/build/clang-plugin/$(DLL_PREFIX)clang-plugin$(DLL_SUFFIX)
+OS_CXXFLAGS += -Xclang -load -Xclang $(CLANG_PLUGIN) -Xclang -add-plugin -Xclang moz-check
+OS_CFLAGS += -Xclang -load -Xclang $(CLANG_PLUGIN) -Xclang -add-plugin -Xclang moz-check
+endif
--- a/configure.in
+++ b/configure.in
@@ -7460,16 +7460,33 @@ if test -n "$DEHYDRA_PATH"; then
     if test ! -f "$DEHYDRA_PATH"; then
         AC_MSG_ERROR([The dehydra plugin is not at the specified path.])
     fi
     AC_DEFINE(NS_STATIC_CHECKING)
 fi
 AC_SUBST(DEHYDRA_PATH)
 
 dnl ========================================================
+dnl = Enable using the clang plugin to build
+dnl ========================================================
+
+MOZ_ARG_ENABLE_BOOL(clang-plugin,
+[  --enable-clang-plugin   Enable building with the mozilla clang plugin ],
+   ENABLE_CLANG_PLUGIN=1,
+   ENABLE_CLANG_PLUGIN= )
+if test -n "$ENABLE_CLANG_PLUGIN"; then
+    if test -z "$CLANG_CC"; then
+        AC_MSG_ERROR([Can't use clang plugin without clang.])
+    fi
+    AC_DEFINE(MOZ_CLANG_PLUGIN)
+fi
+
+AC_SUBST(ENABLE_CLANG_PLUGIN)
+
+dnl ========================================================
 dnl = Enable stripping of libs & executables
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(strip,
 [  --enable-strip          Enable stripping of libs & executables ],
     ENABLE_STRIP=1,
     ENABLE_STRIP= )
 
 dnl ========================================================
@@ -9383,16 +9400,22 @@ CFLAGS="$_SUBDIR_CFLAGS"
 CPPFLAGS="$_SUBDIR_CPPFLAGS"
 CXXFLAGS="$_SUBDIR_CXXFLAGS"
 LDFLAGS="$_SUBDIR_LDFLAGS"
 HOST_CC="$_SUBDIR_HOST_CC"
 HOST_CFLAGS="$_SUBDIR_HOST_CFLAGS"
 HOST_LDFLAGS="$_SUBDIR_HOST_LDFLAGS"
 RC=
 
+if test -n "$ENABLE_CLANG_PLUGIN"; then
+    ac_configure_args="$_SUBDIR_CONFIG_ARGS"
+    AC_OUTPUT_SUBDIRS(build/clang-plugin)
+fi
+
+
 # Run the SpiderMonkey 'configure' script.
 dist=$MOZ_BUILD_ROOT/dist
 ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 ac_configure_args="$ac_configure_args --enable-threadsafe"
 if test "$BUILD_CTYPES"; then
     # Build js-ctypes on the platforms we can.
     ac_configure_args="$ac_configure_args --enable-ctypes"
 fi
--- a/js/src/config/static-checking-config.mk
+++ b/js/src/config/static-checking-config.mk
@@ -21,8 +21,16 @@ DEHYDRA_ARGS = \
   $(DEHYDRA_ARG_PREFIX)treehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(TREEHYDRA_MODULES))) \
   $(NULL)
 
 DEHYDRA_FLAGS = -fplugin=$(DEHYDRA_PATH) $(DEHYDRA_ARGS)
 
 ifdef DEHYDRA_PATH
 OS_CXXFLAGS += $(DEHYDRA_FLAGS)
 endif
+
+ifdef ENABLE_CLANG_PLUGIN
+# Load the clang plugin from the mozilla topsrcdir. This implies that the clang
+# plugin is only usable if we're building js/src under mozilla/, though.
+CLANG_PLUGIN := $(DEPTH)/../../build/clang-plugin/$(DLL_PREFIX)clang-plugin$(DLL_SUFFIX)
+OS_CXXFLAGS += -fplugin=$(CLANG_PLUGIN)
+OS_CFLAGS += -fplugin=$(CLANG_PLUGIN)
+endif
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3747,16 +3747,33 @@ if test -n "$DEHYDRA_PATH"; then
     if test ! -f "$DEHYDRA_PATH"; then
         AC_MSG_ERROR([The dehydra plugin is not at the specified path.])
     fi
     AC_DEFINE(NS_STATIC_CHECKING)
 fi
 AC_SUBST(DEHYDRA_PATH)
 
 dnl ========================================================
+dnl = Enable using the clang plugin to build
+dnl ========================================================
+
+MOZ_ARG_ENABLE_BOOL(clang-plugin,
+[  --enable-clang-plugin   Enable building with the mozilla clang plugin ],
+   ENABLE_CLANG_PLUGIN=1,
+   ENABLE_CLANG_PLUGIN= )
+if test -n "$ENABLE_CLANG_PLUGIN"; then
+    if test -z "$CLANG_CC"; then
+        AC_MSG_ERROR([Can't use clang plugin without clang.])
+    fi
+    AC_DEFINE(MOZ_CLANG_PLUGIN)
+fi
+
+AC_SUBST(ENABLE_CLANG_PLUGIN)
+
+dnl ========================================================
 dnl = Enable static checking using sixgill
 dnl ========================================================
 
 MOZ_ARG_WITH_STRING(sixgill,
 [  --with-sixgill=path/to/sixgill
                           Enable static checking of code using sixgill],
     SIXGILL_PATH=$withval,
     SIXGILL_PATH= )
--- a/moz.build
+++ b/moz.build
@@ -1,15 +1,18 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 CONFIGURE_SUBST_FILES += ['tools/update-packaging/Makefile']
 
+if CONFIG['ENABLE_CLANG_PLUGIN']:
+  add_tier_dir('base', 'build/clang-plugin', static=True)
+
 add_tier_dir('base', ['config', 'build', 'probes', 'mfbt', 'python'])
 
 if not CONFIG['LIBXUL_SDK']:
     if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
         add_tier_dir('base', ['other-licenses/android'])
 
     if CONFIG['MOZ_MEMORY']:
         add_tier_dir('base', ['memory'])