Merge changes from topic 'soong-clang-tidy'

* changes:
  Add clang-tidy support
  Start using "struct Objects" to store object Paths
diff --git a/Android.bp b/Android.bp
index f9ba2c2..74d9c0a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -95,6 +95,7 @@
     srcs: [
         "cc/config/clang.go",
         "cc/config/global.go",
+        "cc/config/tidy.go",
         "cc/config/toolchain.go",
 
         "cc/config/arm_device.go",
@@ -108,6 +109,9 @@
         "cc/config/x86_linux_host.go",
         "cc/config/x86_windows_host.go",
     ],
+    testSrcs: [
+        "cc/config/tidy_test.go",
+    ],
 }
 
 bootstrap_go_package {
@@ -134,6 +138,7 @@
         "cc/sanitize.go",
         "cc/stl.go",
         "cc/strip.go",
+        "cc/tidy.go",
         "cc/util.go",
 
         "cc/compiler.go",
diff --git a/android/config.go b/android/config.go
index 4d7e8df..74cb56e 100644
--- a/android/config.go
+++ b/android/config.go
@@ -384,6 +384,17 @@
 	return Bool(c.ProductVariables.UseGoma)
 }
 
+func (c *config) ClangTidy() bool {
+	return Bool(c.ProductVariables.ClangTidy)
+}
+
+func (c *config) TidyChecks() string {
+	if c.ProductVariables.TidyChecks == nil {
+		return ""
+	}
+	return *c.ProductVariables.TidyChecks
+}
+
 func (c *config) LibartImgHostBaseAddress() string {
 	return "0x60000000"
 }
diff --git a/android/variable.go b/android/variable.go
index a1a2bf0..4aff26e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -112,6 +112,9 @@
 	UseGoma                    *bool `json:",omitempty"`
 	Debuggable                 *bool `json:",omitempty"`
 
+	ClangTidy  *bool   `json:",omitempty"`
+	TidyChecks *string `json:",omitempty"`
+
 	DevicePrefer32BitExecutables *bool `json:",omitempty"`
 	HostPrefer32BitExecutables   *bool `json:",omitempty"`
 
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 1fac4bf..6387ff1 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -53,6 +53,9 @@
 	"LOCAL_EXPORT_SHARED_LIBRARY_HEADERS": {"export_shared_lib_headers", bpparser.ListType},
 	"LOCAL_EXPORT_STATIC_LIBRARY_HEADERS": {"export_static_lib_headers", bpparser.ListType},
 	"LOCAL_INIT_RC":                       {"init_rc", bpparser.ListType},
+	"LOCAL_TIDY_FLAGS":                    {"tidy_flags", bpparser.ListType},
+	// TODO: This is comma-seperated, not space-separated
+	"LOCAL_TIDY_CHECKS": {"tidy_checks", bpparser.ListType},
 
 	"LOCAL_JAVA_RESOURCE_DIRS":    {"java_resource_dirs", bpparser.ListType},
 	"LOCAL_JAVACFLAGS":            {"javacflags", bpparser.ListType},
@@ -73,6 +76,7 @@
 	"LOCAL_RTTI_FLAG":               {"rtti", bpparser.BoolType},
 	"LOCAL_NO_STANDARD_LIBRARIES":   {"no_standard_libraries", bpparser.BoolType},
 	"LOCAL_PACK_MODULE_RELOCATIONS": {"pack_relocations", bpparser.BoolType},
+	"LOCAL_TIDY":                    {"tidy", bpparser.BoolType},
 
 	"LOCAL_EXPORT_PACKAGE_RESOURCES": {"export_package_resources", bpparser.BoolType},
 }
diff --git a/cc/binary.go b/cc/binary.go
index e7d22c1..b029439 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -250,7 +250,7 @@
 }
 
 func (binary *binaryDecorator) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 
 	fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
 	outputFile := android.PathForModuleOut(ctx, fileName)
@@ -282,8 +282,9 @@
 
 	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
+	linkerDeps = append(linkerDeps, objs.tidyFiles...)
 
-	TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, deps.StaticLibs,
+	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
 		deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
 		builderFlags, outputFile)
 
diff --git a/cc/builder.go b/cc/builder.go
index 60aad0b..faa39d1 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -150,6 +150,14 @@
 			Restat:      true,
 		},
 		"crossCompile")
+
+	clangTidy = pctx.AndroidStaticRule("clangTidy",
+		blueprint.RuleParams{
+			Command:     "rm -f $out && ${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out",
+			CommandDeps: []string{"${config.ClangBin}/clang-tidy"},
+			Description: "tidy $out",
+		},
+		"cFlags", "tidyFlags")
 )
 
 func init() {
@@ -174,19 +182,44 @@
 	libFlags    string
 	yaccFlags   string
 	protoFlags  string
+	tidyFlags   string
 	toolchain   config.Toolchain
 	clang       bool
+	tidy        bool
 
 	stripKeepSymbols       bool
 	stripKeepMiniDebugInfo bool
 	stripAddGnuDebuglink   bool
 }
 
+type Objects struct {
+	objFiles  android.Paths
+	tidyFiles android.Paths
+}
+
+func (a Objects) Copy() Objects {
+	return Objects{
+		objFiles:  append(android.Paths{}, a.objFiles...),
+		tidyFiles: append(android.Paths{}, a.tidyFiles...),
+	}
+}
+
+func (a Objects) Append(b Objects) Objects {
+	return Objects{
+		objFiles:  append(a.objFiles, b.objFiles...),
+		tidyFiles: append(a.tidyFiles, b.tidyFiles...),
+	}
+}
+
 // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
 func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles android.Paths,
-	flags builderFlags, deps android.Paths) (objFiles android.Paths) {
+	flags builderFlags, deps android.Paths) Objects {
 
-	objFiles = make(android.Paths, len(srcFiles))
+	objFiles := make(android.Paths, len(srcFiles))
+	var tidyFiles android.Paths
+	if flags.tidy && flags.clang {
+		tidyFiles = make(android.Paths, 0, len(srcFiles))
+	}
 
 	cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
 	cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
@@ -207,11 +240,13 @@
 
 		var moduleCflags string
 		var ccCmd string
+		tidy := flags.tidy && flags.clang
 
 		switch srcFile.Ext() {
 		case ".S", ".s":
 			ccCmd = "gcc"
 			moduleCflags = asflags
+			tidy = false
 		case ".c":
 			ccCmd = "gcc"
 			moduleCflags = cflags
@@ -248,22 +283,45 @@
 				"ccCmd":  ccCmd,
 			},
 		})
+
+		if tidy {
+			tidyFile := android.ObjPathWithExt(ctx, srcFile, subdir, "tidy")
+			tidyFiles = append(tidyFiles, tidyFile)
+
+			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+				Rule:   clangTidy,
+				Output: tidyFile,
+				Input:  srcFile,
+				// We must depend on objFile, since clang-tidy doesn't
+				// support exporting dependencies.
+				Implicit: objFile,
+				Args: map[string]string{
+					"cFlags":    moduleCflags,
+					"tidyFlags": flags.tidyFlags,
+				},
+			})
+		}
+
 	}
 
-	return objFiles
+	return Objects{
+		objFiles:  objFiles,
+		tidyFiles: tidyFiles,
+	}
 }
 
 // Generate a rule for compiling multiple .o files to a static library (.a)
 func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
-	flags builderFlags, outputFile android.ModuleOutPath) {
+	flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
 
 	arCmd := gccCmd(flags.toolchain, "ar")
 	arFlags := "crsPD"
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   ar,
-		Output: outputFile,
-		Inputs: objFiles,
+		Rule:      ar,
+		Output:    outputFile,
+		Inputs:    objFiles,
+		Implicits: deps,
 		Args: map[string]string{
 			"arFlags": arFlags,
 			"arCmd":   arCmd,
@@ -276,7 +334,7 @@
 // very small command line length limit, so we have to split the ar into multiple
 // steps, each appending to the previous one.
 func TransformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
-	flags builderFlags, outputPath android.ModuleOutPath) {
+	flags builderFlags, outputPath android.ModuleOutPath, deps android.Paths) {
 
 	arFlags := "cqs"
 
@@ -285,8 +343,9 @@
 		dummyAr := android.PathForModuleOut(ctx, "dummy"+staticLibraryExtension)
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-			Rule:   emptyFile,
-			Output: dummy,
+			Rule:      emptyFile,
+			Output:    dummy,
+			Implicits: deps,
 		})
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
@@ -329,9 +388,10 @@
 
 		if in == "" {
 			ctx.Build(pctx, blueprint.BuildParams{
-				Rule:    darwinAr,
-				Outputs: []string{out},
-				Inputs:  l,
+				Rule:      darwinAr,
+				Outputs:   []string{out},
+				Inputs:    l,
+				Implicits: deps.Strings(),
 				Args: map[string]string{
 					"arFlags": arFlags,
 				},
diff --git a/cc/cc.go b/cc/cc.go
index 33c9611..b6e98b1 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -76,8 +76,8 @@
 	StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
 
 	// Paths to .o files
-	ObjFiles               android.Paths
-	WholeStaticLibObjFiles android.Paths
+	Objs               Objects
+	WholeStaticLibObjs Objects
 
 	// Paths to generated source files
 	GeneratedSources android.Paths
@@ -100,9 +100,11 @@
 	protoFlags  []string // Flags that apply to proto source files
 	LdFlags     []string // Flags that apply to linker command lines
 	libFlags    []string // Flags to add libraries early to the link order
+	TidyFlags   []string // Flags that apply to clang-tidy
 
 	Toolchain config.Toolchain
 	Clang     bool
+	Tidy      bool
 
 	RequiredInstructionSet string
 	DynamicLinker          string
@@ -174,7 +176,7 @@
 
 	appendCflags([]string)
 	appendAsflags([]string)
-	compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths
+	compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects
 }
 
 type linker interface {
@@ -183,7 +185,7 @@
 	linkerFlags(ctx ModuleContext, flags Flags) Flags
 	linkerProps() []interface{}
 
-	link(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path
+	link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path
 	appendLdflags([]string)
 }
 
@@ -368,6 +370,9 @@
 
 func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	module := newBaseModule(hod, multilib)
+	module.features = []feature{
+		&tidyFeature{},
+	}
 	module.stl = &stl{}
 	module.sanitize = &sanitize{}
 	return module
@@ -440,16 +445,16 @@
 
 	flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...)
 
-	var objFiles android.Paths
+	var objs Objects
 	if c.compiler != nil {
-		objFiles = c.compiler.compile(ctx, flags, deps)
+		objs = c.compiler.compile(ctx, flags, deps)
 		if ctx.Failed() {
 			return
 		}
 	}
 
 	if c.linker != nil {
-		outputFile := c.linker.link(ctx, flags, deps, objFiles)
+		outputFile := c.linker.link(ctx, flags, deps, objs)
 		if ctx.Failed() {
 			return
 		}
@@ -813,8 +818,7 @@
 		}
 
 		if tag == reuseObjTag {
-			depPaths.ObjFiles = append(depPaths.ObjFiles,
-				cc.compiler.(libraryInterface).reuseObjs()...)
+			depPaths.Objs = depPaths.Objs.Append(cc.compiler.(libraryInterface).reuseObjs())
 			return
 		}
 
@@ -868,10 +872,9 @@
 				}
 				ctx.AddMissingDependencies(missingDeps)
 			}
-			depPaths.WholeStaticLibObjFiles =
-				append(depPaths.WholeStaticLibObjFiles, staticLib.objs()...)
+			depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
 		case objDepTag:
-			ptr = &depPaths.ObjFiles
+			depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
 		case crtBeginDepTag:
 			depPaths.CrtBegin = linkFile
 		case crtEndDepTag:
@@ -950,6 +953,7 @@
 		&SanitizeProperties{},
 		&StripProperties{},
 		&InstallerProperties{},
+		&TidyProperties{},
 	)
 
 	return android.InitDefaultsModule(module, module, props...)
diff --git a/cc/check.go b/cc/check.go
index 4e403a5..340464e 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -105,3 +105,31 @@
 		}
 	}
 }
+
+// Check for bad clang tidy flags
+func CheckBadTidyFlags(ctx ModuleContext, prop string, flags []string) {
+	for _, flag := range flags {
+		flag = strings.TrimSpace(flag)
+
+		if !strings.HasPrefix(flag, "-") {
+			ctx.PropertyErrorf(prop, "Flag `%s` must start with `-`", flag)
+		} else if strings.HasPrefix(flag, "-fix") {
+			ctx.PropertyErrorf(prop, "Flag `%s` is not allowed, since it could cause multiple writes to the same source file", flag)
+		} else if strings.HasPrefix(flag, "-checks=") {
+			ctx.PropertyErrorf(prop, "Flag `%s` is not allowed, use `tidy_checks` property instead", flag)
+		} else if strings.Contains(flag, " ") {
+			ctx.PropertyErrorf(prop, "Bad flag: `%s` is not an allowed multi-word flag. Should it be split into multiple flags?", flag)
+		}
+	}
+}
+
+// Check for bad clang tidy checks
+func CheckBadTidyChecks(ctx ModuleContext, prop string, checks []string) {
+	for _, check := range checks {
+		if strings.Contains(check, " ") {
+			ctx.PropertyErrorf("tidy_checks", "Check `%s` invalid, cannot contain spaces", check)
+		} else if strings.Contains(check, ",") {
+			ctx.PropertyErrorf("tidy_checks", "Check `%s` invalid, cannot contain commas. Split each entry into it's own string instead", check)
+		}
+	}
+}
diff --git a/cc/compiler.go b/cc/compiler.go
index 0184ee9..454be5e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -350,7 +350,7 @@
 	return nil
 }
 
-func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
+func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	pathDeps := deps.GeneratedHeaders
 	pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
 
@@ -367,18 +367,18 @@
 	compiler.deps = pathDeps
 
 	// Compile files listed in c.Properties.Srcs into objects
-	objFiles := compileObjs(ctx, buildFlags, "", srcs, compiler.deps)
+	objs := compileObjs(ctx, buildFlags, "", srcs, compiler.deps)
 
 	if ctx.Failed() {
-		return nil
+		return Objects{}
 	}
 
-	return objFiles
+	return objs
 }
 
 // Compile a list of source files into objects a specified subdirectory
 func compileObjs(ctx android.ModuleContext, flags builderFlags,
-	subdir string, srcFiles, deps android.Paths) android.Paths {
+	subdir string, srcFiles, deps android.Paths) Objects {
 
 	return TransformSourceToObj(ctx, subdir, srcFiles, flags, deps)
 }
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
new file mode 100644
index 0000000..dd39421
--- /dev/null
+++ b/cc/config/tidy.go
@@ -0,0 +1,106 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+	"strings"
+)
+
+func init() {
+	// Most Android source files are not clang-tidy clean yet.
+	// Global tidy checks include only google*, performance*,
+	// and misc-macro-parentheses, but not google-readability*
+	// or google-runtime-references.
+	pctx.StaticVariable("TidyDefaultGlobalChecks", strings.Join([]string{
+		"-*",
+		"google*",
+		"misc-macro-parentheses",
+		"performance*",
+		"-google-readability*",
+		"-google-runtime-references",
+	}, ","))
+
+	// There are too many clang-tidy warnings in external and vendor projects.
+	// Enable only some google checks for these projects.
+	pctx.StaticVariable("TidyExternalVendorChecks", strings.Join([]string{
+		"-*",
+		"google*",
+		"-google-build-using-namespace",
+		"-google-default-arguments",
+		"-google-explicit-constructor",
+		"-google-readability*",
+		"-google-runtime-int",
+		"-google-runtime-references",
+	}, ","))
+
+	// Give warnings to header files only in selected directories.
+	// Do not give warnings to external or vendor header files, which contain too
+	// many warnings.
+	pctx.StaticVariable("TidyDefaultHeaderDirs", strings.Join([]string{
+		"art/",
+		"bionic/",
+		"bootable/",
+		"build/",
+		"cts/",
+		"dalvik/",
+		"developers/",
+		"development/",
+		"frameworks/",
+		"libcore/",
+		"libnativehelper/",
+		"system/",
+	}, "|"))
+}
+
+type PathBasedTidyCheck struct {
+	PathPrefix string
+	Checks     string
+}
+
+const tidyDefault = "${config.TidyDefaultGlobalChecks}"
+const tidyExternalVendor = "${config.TidyExternalVendorChecks}"
+
+// This is a map of local path prefixes to the set of default clang-tidy checks
+// to be used.
+// The last matched local_path_prefix should be the most specific to be used.
+var DefaultLocalTidyChecks = []PathBasedTidyCheck{
+	{"external/", tidyExternalVendor},
+	{"external/google", tidyDefault},
+	{"external/webrtc", tidyDefault},
+	{"frameworks/compile/mclinker/", tidyExternalVendor},
+	{"hardware/qcom", tidyExternalVendor},
+	{"vendor/", tidyExternalVendor},
+	{"vendor/google", tidyDefault},
+	{"vendor/google_devices", tidyExternalVendor},
+}
+
+var reversedDefaultLocalTidyChecks = reverseTidyChecks(DefaultLocalTidyChecks)
+
+func reverseTidyChecks(in []PathBasedTidyCheck) []PathBasedTidyCheck {
+	ret := make([]PathBasedTidyCheck, len(in))
+	for i, check := range in {
+		ret[len(in)-i-1] = check
+	}
+	return ret
+}
+
+func TidyChecksForDir(dir string) string {
+	for _, pathCheck := range reversedDefaultLocalTidyChecks {
+		if strings.HasPrefix(dir, pathCheck.PathPrefix) {
+			return pathCheck.Checks
+		}
+	}
+	return tidyDefault
+}
diff --git a/cc/config/tidy_test.go b/cc/config/tidy_test.go
new file mode 100644
index 0000000..4ed8b23
--- /dev/null
+++ b/cc/config/tidy_test.go
@@ -0,0 +1,41 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+	"testing"
+)
+
+func TestTidyChecksForDir(t *testing.T) {
+	testCases := []struct {
+		input    string
+		expected string
+	}{
+		{"foo/bar", tidyDefault},
+		{"vendor/foo/bar", tidyExternalVendor},
+		{"vendor/google", tidyDefault},
+		{"vendor/google/foo", tidyDefault},
+		{"vendor/google_devices/foo", tidyExternalVendor},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.input, func(t *testing.T) {
+			output := TidyChecksForDir(testCase.input)
+			if output != testCase.expected {
+				t.Error("Output doesn't match expected", output, testCase.expected)
+			}
+		})
+	}
+}
diff --git a/cc/library.go b/cc/library.go
index 99a9b48..dcfc077 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -160,7 +160,7 @@
 	Properties LibraryProperties
 
 	// For reusing static library objects for shared library
-	reuseObjFiles android.Paths
+	reuseObjects Objects
 	// table-of-contents file to optimize out relinking when possible
 	tocFile android.OptionalPath
 
@@ -173,7 +173,7 @@
 	wholeStaticMissingDeps []string
 
 	// For whole_static_libs
-	objFiles android.Paths
+	objects Objects
 
 	// Uses the module's name if empty, but can be overridden. Does not include
 	// shlib suffix.
@@ -251,31 +251,29 @@
 	return flags
 }
 
-func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
-	var objFiles android.Paths
-
-	objFiles = library.baseCompiler.compile(ctx, flags, deps)
-	library.reuseObjFiles = objFiles
+func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+	objs := library.baseCompiler.compile(ctx, flags, deps)
+	library.reuseObjects = objs
 	buildFlags := flagsToBuilderFlags(flags)
 
 	if library.static() {
 		srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
-		objFiles = append(objFiles, compileObjs(ctx, buildFlags, android.DeviceStaticLibrary,
-			srcs, library.baseCompiler.deps)...)
+		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary,
+			srcs, library.baseCompiler.deps))
 	} else {
 		srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
-		objFiles = append(objFiles, compileObjs(ctx, buildFlags, android.DeviceSharedLibrary,
-			srcs, library.baseCompiler.deps)...)
+		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary,
+			srcs, library.baseCompiler.deps))
 	}
 
-	return objFiles
+	return objs
 }
 
 type libraryInterface interface {
 	getWholeStaticMissingDeps() []string
 	static() bool
-	objs() android.Paths
-	reuseObjs() android.Paths
+	objs() Objects
+	reuseObjs() Objects
 	toc() android.OptionalPath
 
 	// Returns true if the build options for the module have selected a static or shared build
@@ -340,18 +338,18 @@
 }
 
 func (library *libraryDecorator) linkStatic(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 
-	library.objFiles = append(android.Paths{}, deps.WholeStaticLibObjFiles...)
-	library.objFiles = append(library.objFiles, objFiles...)
+	library.objects = deps.WholeStaticLibObjs.Copy()
+	library.objects = library.objects.Append(objs)
 
 	outputFile := android.PathForModuleOut(ctx,
 		ctx.ModuleName()+library.Properties.VariantName+staticLibraryExtension)
 
 	if ctx.Darwin() {
-		TransformDarwinObjToStaticLib(ctx, library.objFiles, flagsToBuilderFlags(flags), outputFile)
+		TransformDarwinObjToStaticLib(ctx, library.objects.objFiles, flagsToBuilderFlags(flags), outputFile, objs.tidyFiles)
 	} else {
-		TransformObjToStaticLib(ctx, library.objFiles, flagsToBuilderFlags(flags), outputFile)
+		TransformObjToStaticLib(ctx, library.objects.objFiles, flagsToBuilderFlags(flags), outputFile, objs.tidyFiles)
 	}
 
 	library.wholeStaticMissingDeps = ctx.GetMissingDependencies()
@@ -362,7 +360,7 @@
 }
 
 func (library *libraryDecorator) linkShared(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 
 	var linkerDeps android.Paths
 
@@ -454,8 +452,9 @@
 
 	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
+	linkerDeps = append(linkerDeps, objs.tidyFiles...)
 
-	TransformObjToDynamicBinary(ctx, objFiles, sharedLibs,
+	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
 		deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
 		linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
 
@@ -463,15 +462,15 @@
 }
 
 func (library *libraryDecorator) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 
-	objFiles = append(objFiles, deps.ObjFiles...)
+	objs = objs.Append(deps.Objs)
 
 	var out android.Path
 	if library.static() {
-		out = library.linkStatic(ctx, flags, deps, objFiles)
+		out = library.linkStatic(ctx, flags, deps, objs)
 	} else {
-		out = library.linkShared(ctx, flags, deps, objFiles)
+		out = library.linkShared(ctx, flags, deps, objs)
 	}
 
 	library.exportIncludes(ctx, "-I")
@@ -505,12 +504,12 @@
 	return library.wholeStaticMissingDeps
 }
 
-func (library *libraryDecorator) objs() android.Paths {
-	return library.objFiles
+func (library *libraryDecorator) objs() Objects {
+	return library.objects
 }
 
-func (library *libraryDecorator) reuseObjs() android.Paths {
-	return library.reuseObjFiles
+func (library *libraryDecorator) reuseObjs() Objects {
+	return library.reuseObjects
 }
 
 func (library *libraryDecorator) toc() android.OptionalPath {
diff --git a/cc/linker.go b/cc/linker.go
index 0923338..28572c6 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -197,6 +197,6 @@
 }
 
 func (linker *baseLinker) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 	panic(fmt.Errorf("baseLinker doesn't know how to link"))
 }
diff --git a/cc/makevars.go b/cc/makevars.go
index 770e1d0..7f1063f 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -36,6 +36,7 @@
 	ctx.Strict("CLANG_CXX", "${config.ClangBin}/clang++")
 	ctx.Strict("LLVM_AS", "${config.ClangBin}/llvm-as")
 	ctx.Strict("LLVM_LINK", "${config.ClangBin}/llvm-link")
+	ctx.Strict("PATH_TO_CLANG_TIDY", "${config.ClangBin}/clang-tidy")
 	ctx.StrictSorted("CLANG_CONFIG_UNKNOWN_CFLAGS", strings.Join(config.ClangUnknownCflags, " "))
 
 	ctx.Strict("GLOBAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideGlobalCflags}")
@@ -52,6 +53,10 @@
 	ctx.Strict("DEFAULT_CPP_STD_VERSION", config.CppStdVersion)
 	ctx.Strict("DEFAULT_GCC_CPP_STD_VERSION", config.GccCppStdVersion)
 
+	ctx.Strict("DEFAULT_GLOBAL_TIDY_CHECKS", "${config.TidyDefaultGlobalChecks}")
+	ctx.Strict("DEFAULT_LOCAL_TIDY_CHECKS", joinLocalTidyChecks(config.DefaultLocalTidyChecks))
+	ctx.Strict("DEFAULT_TIDY_HEADER_DIRS", "${config.TidyDefaultHeaderDirs}")
+
 	includeFlags, err := ctx.Eval("${config.CommonGlobalIncludes} ${config.CommonGlobalSystemIncludes}")
 	if err != nil {
 		panic(err)
@@ -257,3 +262,11 @@
 
 	return includes, systemIncludes
 }
+
+func joinLocalTidyChecks(checks []config.PathBasedTidyCheck) string {
+	rets := make([]string, len(checks))
+	for i, check := range config.DefaultLocalTidyChecks {
+		rets[i] = check.PathPrefix + ":" + check.Checks
+	}
+	return strings.Join(rets, " ")
+}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 6b0c325..48fbf4d 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -189,7 +189,7 @@
 	ndkMigratedLibs = append(ndkMigratedLibs, name)
 }
 
-func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
+func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	arch := ctx.Arch().ArchType.String()
 
 	if !strings.HasSuffix(ctx.ModuleName(), ndkLibrarySuffix) {
@@ -242,11 +242,11 @@
 }
 
 func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
-	objFiles android.Paths) android.Path {
+	objs Objects) android.Path {
 
 	linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
 	flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
-	return stub.libraryDecorator.link(ctx, flags, deps, objFiles)
+	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
 func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 106c9b5..46b383b 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -79,7 +79,7 @@
 }
 
 func (c *ndkPrebuiltObjectLinker) link(ctx ModuleContext, flags Flags,
-	deps PathDeps, objFiles android.Paths) android.Path {
+	deps PathDeps, objs Objects) android.Path {
 	// A null build step, but it sets up the output path.
 	if !strings.HasPrefix(ctx.ModuleName(), "ndk_crt") {
 		ctx.ModuleErrorf("NDK prebuilts must have an ndk_crt prefixed name")
@@ -115,7 +115,7 @@
 }
 
 func (ndk *ndkPrebuiltLibraryLinker) link(ctx ModuleContext, flags Flags,
-	deps PathDeps, objFiles android.Paths) android.Path {
+	deps PathDeps, objs Objects) android.Path {
 	// A null build step, but it sets up the output path.
 	ndk.exportIncludes(ctx, "-isystem")
 
@@ -181,7 +181,7 @@
 }
 
 func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags,
-	deps PathDeps, objFiles android.Paths) android.Path {
+	deps PathDeps, objs Objects) android.Path {
 	// A null build step, but it sets up the output path.
 	if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") {
 		ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name")
diff --git a/cc/object.go b/cc/object.go
index 72fd55b..57cc8b0 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -70,16 +70,16 @@
 }
 
 func (object *objectLinker) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 
-	objFiles = append(objFiles, deps.ObjFiles...)
+	objs = objs.Append(deps.Objs)
 
 	var outputFile android.Path
-	if len(objFiles) == 1 {
-		outputFile = objFiles[0]
+	if len(objs.objFiles) == 1 {
+		outputFile = objs.objFiles[0]
 	} else {
 		output := android.PathForModuleOut(ctx, ctx.ModuleName()+objectExtension)
-		TransformObjsToObj(ctx, objFiles, flagsToBuilderFlags(flags), output)
+		TransformObjsToObj(ctx, objs.objFiles, flagsToBuilderFlags(flags), output)
 		outputFile = output
 	}
 
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 55775b6..4328df8 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -46,7 +46,7 @@
 }
 
 func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 	// TODO(ccross): verify shared library dependencies
 	if len(p.Prebuilt.Properties.Srcs) > 0 {
 		p.libraryDecorator.exportIncludes(ctx, "-I")
diff --git a/cc/tidy.go b/cc/tidy.go
new file mode 100644
index 0000000..68380ec
--- /dev/null
+++ b/cc/tidy.go
@@ -0,0 +1,93 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/cc/config"
+)
+
+type TidyProperties struct {
+	// whether to run clang-tidy over C-like sources.
+	Tidy *bool
+
+	// Extra flags to pass to clang-tidy
+	Tidy_flags []string
+
+	// Extra checks to enable or disable in clang-tidy
+	Tidy_checks []string
+}
+
+type tidyFeature struct {
+	Properties TidyProperties
+}
+
+func (tidy *tidyFeature) props() []interface{} {
+	return []interface{}{&tidy.Properties}
+}
+
+func (tidy *tidyFeature) begin(ctx BaseModuleContext) {
+}
+
+func (tidy *tidyFeature) deps(ctx BaseModuleContext, deps Deps) Deps {
+	return deps
+}
+
+func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
+	// Check if tidy is explicitly disabled for this module
+	if tidy.Properties.Tidy != nil && !*tidy.Properties.Tidy {
+		return flags
+	}
+
+	// If not explicitly set, check the global tidy flag
+	if tidy.Properties.Tidy == nil && !ctx.AConfig().ClangTidy() {
+		return flags
+	}
+
+	// Clang-tidy requires clang
+	if !flags.Clang {
+		return flags
+	}
+
+	flags.Tidy = true
+
+	CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
+
+	esc := proptools.NinjaAndShellEscape
+
+	flags.TidyFlags = append(flags.TidyFlags, esc(tidy.Properties.Tidy_flags)...)
+	if len(flags.TidyFlags) == 0 {
+		headerFilter := "-header-filter=\"(" + ctx.ModuleDir() + "|${config.TidyDefaultHeaderDirs})\""
+		flags.TidyFlags = append(flags.TidyFlags, headerFilter)
+	}
+
+	tidyChecks := "-checks="
+	if checks := ctx.AConfig().TidyChecks(); len(checks) > 0 {
+		tidyChecks += checks
+	} else {
+		tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
+	}
+	if len(tidy.Properties.Tidy_checks) > 0 {
+		CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
+
+		tidyChecks = tidyChecks + "," + strings.Join(esc(tidy.Properties.Tidy_checks), ",")
+	}
+	flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
+
+	return flags
+}
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 0097ca3..2f3c9a1 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -53,12 +53,12 @@
 }
 
 func (library *toolchainLibraryDecorator) compile(ctx ModuleContext, flags Flags,
-	deps PathDeps) android.Paths {
-	return nil
+	deps PathDeps) Objects {
+	return Objects{}
 }
 
 func (library *toolchainLibraryDecorator) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
+	flags Flags, deps PathDeps, objs Objects) android.Path {
 
 	libName := ctx.ModuleName() + staticLibraryExtension
 	outputFile := android.PathForModuleOut(ctx, libName)
diff --git a/cc/util.go b/cc/util.go
index 07296b9..31f0aec 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -96,8 +96,10 @@
 		protoFlags:  strings.Join(in.protoFlags, " "),
 		ldFlags:     strings.Join(in.LdFlags, " "),
 		libFlags:    strings.Join(in.libFlags, " "),
+		tidyFlags:   strings.Join(in.TidyFlags, " "),
 		toolchain:   in.Toolchain,
 		clang:       in.Clang,
+		tidy:        in.Tidy,
 	}
 }