xref: /aosp_15_r20/build/soong/cc/tidy.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2016 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage cc
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
20*333d2b36SAndroid Build Coastguard Worker	"regexp"
21*333d2b36SAndroid Build Coastguard Worker	"strings"
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
24*333d2b36SAndroid Build Coastguard Worker
25*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
26*333d2b36SAndroid Build Coastguard Worker	"android/soong/cc/config"
27*333d2b36SAndroid Build Coastguard Worker)
28*333d2b36SAndroid Build Coastguard Worker
29*333d2b36SAndroid Build Coastguard Workertype TidyProperties struct {
30*333d2b36SAndroid Build Coastguard Worker	// whether to run clang-tidy over C-like sources.
31*333d2b36SAndroid Build Coastguard Worker	Tidy *bool
32*333d2b36SAndroid Build Coastguard Worker
33*333d2b36SAndroid Build Coastguard Worker	// Extra flags to pass to clang-tidy
34*333d2b36SAndroid Build Coastguard Worker	Tidy_flags []string
35*333d2b36SAndroid Build Coastguard Worker
36*333d2b36SAndroid Build Coastguard Worker	// Extra checks to enable or disable in clang-tidy
37*333d2b36SAndroid Build Coastguard Worker	Tidy_checks []string
38*333d2b36SAndroid Build Coastguard Worker
39*333d2b36SAndroid Build Coastguard Worker	// Checks that should be treated as errors.
40*333d2b36SAndroid Build Coastguard Worker	Tidy_checks_as_errors []string
41*333d2b36SAndroid Build Coastguard Worker}
42*333d2b36SAndroid Build Coastguard Worker
43*333d2b36SAndroid Build Coastguard Workertype tidyFeature struct {
44*333d2b36SAndroid Build Coastguard Worker	Properties TidyProperties
45*333d2b36SAndroid Build Coastguard Worker}
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Workervar quotedFlagRegexp, _ = regexp.Compile(`^-?-[^=]+=('|").*('|")$`)
48*333d2b36SAndroid Build Coastguard Worker
49*333d2b36SAndroid Build Coastguard Worker// When passing flag -name=value, if user add quotes around 'value',
50*333d2b36SAndroid Build Coastguard Worker// the quotation marks will be preserved by NinjaAndShellEscapeList
51*333d2b36SAndroid Build Coastguard Worker// and the 'value' string with quotes won't work like the intended value.
52*333d2b36SAndroid Build Coastguard Worker// So here we report an error if -*='*' is found.
53*333d2b36SAndroid Build Coastguard Workerfunc checkNinjaAndShellEscapeList(ctx ModuleContext, prop string, slice []string) []string {
54*333d2b36SAndroid Build Coastguard Worker	for _, s := range slice {
55*333d2b36SAndroid Build Coastguard Worker		if quotedFlagRegexp.MatchString(s) {
56*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf(prop, "Extra quotes in: %s", s)
57*333d2b36SAndroid Build Coastguard Worker		}
58*333d2b36SAndroid Build Coastguard Worker	}
59*333d2b36SAndroid Build Coastguard Worker	return proptools.NinjaAndShellEscapeList(slice)
60*333d2b36SAndroid Build Coastguard Worker}
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Workerfunc (tidy *tidyFeature) props() []interface{} {
63*333d2b36SAndroid Build Coastguard Worker	return []interface{}{&tidy.Properties}
64*333d2b36SAndroid Build Coastguard Worker}
65*333d2b36SAndroid Build Coastguard Worker
66*333d2b36SAndroid Build Coastguard Worker// Set this const to true when all -warnings-as-errors in tidy_flags
67*333d2b36SAndroid Build Coastguard Worker// are replaced with tidy_checks_as_errors.
68*333d2b36SAndroid Build Coastguard Worker// Then, that old style usage will be obsolete and an error.
69*333d2b36SAndroid Build Coastguard Workerconst NoWarningsAsErrorsInTidyFlags = true
70*333d2b36SAndroid Build Coastguard Worker
71*333d2b36SAndroid Build Coastguard Workerfunc (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
72*333d2b36SAndroid Build Coastguard Worker	CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
73*333d2b36SAndroid Build Coastguard Worker	CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
74*333d2b36SAndroid Build Coastguard Worker
75*333d2b36SAndroid Build Coastguard Worker	// Check if tidy is explicitly disabled for this module
76*333d2b36SAndroid Build Coastguard Worker	if tidy.Properties.Tidy != nil && !*tidy.Properties.Tidy {
77*333d2b36SAndroid Build Coastguard Worker		return flags
78*333d2b36SAndroid Build Coastguard Worker	}
79*333d2b36SAndroid Build Coastguard Worker	// Some projects like external/* and vendor/* have clang-tidy disabled by default,
80*333d2b36SAndroid Build Coastguard Worker	// unless they are enabled explicitly with the "tidy:true" property or
81*333d2b36SAndroid Build Coastguard Worker	// when TIDY_EXTERNAL_VENDOR is set to true.
82*333d2b36SAndroid Build Coastguard Worker	if !proptools.Bool(tidy.Properties.Tidy) &&
83*333d2b36SAndroid Build Coastguard Worker		config.NoClangTidyForDir(
84*333d2b36SAndroid Build Coastguard Worker			ctx.Config().IsEnvTrue("TIDY_EXTERNAL_VENDOR"),
85*333d2b36SAndroid Build Coastguard Worker			ctx.ModuleDir()) {
86*333d2b36SAndroid Build Coastguard Worker		return flags
87*333d2b36SAndroid Build Coastguard Worker	}
88*333d2b36SAndroid Build Coastguard Worker	// If not explicitly disabled, set flags.Tidy to generate .tidy rules.
89*333d2b36SAndroid Build Coastguard Worker	// Note that libraries and binaries will depend on .tidy files ONLY if
90*333d2b36SAndroid Build Coastguard Worker	// the global WITH_TIDY or module 'tidy' property is true.
91*333d2b36SAndroid Build Coastguard Worker	flags.Tidy = true
92*333d2b36SAndroid Build Coastguard Worker
93*333d2b36SAndroid Build Coastguard Worker	// If explicitly enabled, by global WITH_TIDY or local tidy:true property,
94*333d2b36SAndroid Build Coastguard Worker	// set flags.NeedTidyFiles to make this module depend on .tidy files.
95*333d2b36SAndroid Build Coastguard Worker	// Note that locally set tidy:true is ignored if ALLOW_LOCAL_TIDY_TRUE is not set to true.
96*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().IsEnvTrue("WITH_TIDY") || (ctx.Config().IsEnvTrue("ALLOW_LOCAL_TIDY_TRUE") && Bool(tidy.Properties.Tidy)) {
97*333d2b36SAndroid Build Coastguard Worker		flags.NeedTidyFiles = true
98*333d2b36SAndroid Build Coastguard Worker	}
99*333d2b36SAndroid Build Coastguard Worker
100*333d2b36SAndroid Build Coastguard Worker	// Add global WITH_TIDY_FLAGS and local tidy_flags.
101*333d2b36SAndroid Build Coastguard Worker	withTidyFlags := ctx.Config().Getenv("WITH_TIDY_FLAGS")
102*333d2b36SAndroid Build Coastguard Worker	if len(withTidyFlags) > 0 {
103*333d2b36SAndroid Build Coastguard Worker		flags.TidyFlags = append(flags.TidyFlags, withTidyFlags)
104*333d2b36SAndroid Build Coastguard Worker	}
105*333d2b36SAndroid Build Coastguard Worker	esc := checkNinjaAndShellEscapeList
106*333d2b36SAndroid Build Coastguard Worker	flags.TidyFlags = append(flags.TidyFlags, esc(ctx, "tidy_flags", tidy.Properties.Tidy_flags)...)
107*333d2b36SAndroid Build Coastguard Worker	// If TidyFlags does not contain -header-filter, add default header filter.
108*333d2b36SAndroid Build Coastguard Worker	// Find the substring because the flag could also appear as --header-filter=...
109*333d2b36SAndroid Build Coastguard Worker	// and with or without single or double quotes.
110*333d2b36SAndroid Build Coastguard Worker	if !android.SubstringInList(flags.TidyFlags, "-header-filter=") {
111*333d2b36SAndroid Build Coastguard Worker		defaultDirs := ctx.Config().Getenv("DEFAULT_TIDY_HEADER_DIRS")
112*333d2b36SAndroid Build Coastguard Worker		headerFilter := "-header-filter="
113*333d2b36SAndroid Build Coastguard Worker		// Default header filter should include only the module directory,
114*333d2b36SAndroid Build Coastguard Worker		// not the out/soong/.../ModuleDir/...
115*333d2b36SAndroid Build Coastguard Worker		// Otherwise, there will be too many warnings from generated files in out/...
116*333d2b36SAndroid Build Coastguard Worker		// If a module wants to see warnings in the generated source files,
117*333d2b36SAndroid Build Coastguard Worker		// it should specify its own -header-filter flag.
118*333d2b36SAndroid Build Coastguard Worker		if defaultDirs == "" {
119*333d2b36SAndroid Build Coastguard Worker			headerFilter += "^" + ctx.ModuleDir() + "/"
120*333d2b36SAndroid Build Coastguard Worker		} else {
121*333d2b36SAndroid Build Coastguard Worker			headerFilter += "\"(^" + ctx.ModuleDir() + "/|" + defaultDirs + ")\""
122*333d2b36SAndroid Build Coastguard Worker		}
123*333d2b36SAndroid Build Coastguard Worker		flags.TidyFlags = append(flags.TidyFlags, headerFilter)
124*333d2b36SAndroid Build Coastguard Worker	}
125*333d2b36SAndroid Build Coastguard Worker	// Work around RBE bug in parsing clang-tidy flags, replace "--flag" with "-flag".
126*333d2b36SAndroid Build Coastguard Worker	// Some C/C++ modules added local tidy flags like --header-filter= and --extra-arg-before=.
127*333d2b36SAndroid Build Coastguard Worker	doubleDash := regexp.MustCompile("^('?)--(.*)$")
128*333d2b36SAndroid Build Coastguard Worker	for i, s := range flags.TidyFlags {
129*333d2b36SAndroid Build Coastguard Worker		flags.TidyFlags[i] = doubleDash.ReplaceAllString(s, "$1-$2")
130*333d2b36SAndroid Build Coastguard Worker	}
131*333d2b36SAndroid Build Coastguard Worker
132*333d2b36SAndroid Build Coastguard Worker	// If clang-tidy is not enabled globally, add the -quiet flag.
133*333d2b36SAndroid Build Coastguard Worker	if !ctx.Config().ClangTidy() {
134*333d2b36SAndroid Build Coastguard Worker		flags.TidyFlags = append(flags.TidyFlags, "-quiet")
135*333d2b36SAndroid Build Coastguard Worker		flags.TidyFlags = append(flags.TidyFlags, "-extra-arg-before=-fno-caret-diagnostics")
136*333d2b36SAndroid Build Coastguard Worker	}
137*333d2b36SAndroid Build Coastguard Worker
138*333d2b36SAndroid Build Coastguard Worker	for _, f := range config.TidyExtraArgFlags() {
139*333d2b36SAndroid Build Coastguard Worker		flags.TidyFlags = append(flags.TidyFlags, "-extra-arg-before="+f)
140*333d2b36SAndroid Build Coastguard Worker	}
141*333d2b36SAndroid Build Coastguard Worker
142*333d2b36SAndroid Build Coastguard Worker	tidyChecks := "-checks="
143*333d2b36SAndroid Build Coastguard Worker	if checks := ctx.Config().TidyChecks(); len(checks) > 0 {
144*333d2b36SAndroid Build Coastguard Worker		tidyChecks += checks
145*333d2b36SAndroid Build Coastguard Worker	} else {
146*333d2b36SAndroid Build Coastguard Worker		tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
147*333d2b36SAndroid Build Coastguard Worker	}
148*333d2b36SAndroid Build Coastguard Worker	if len(tidy.Properties.Tidy_checks) > 0 {
149*333d2b36SAndroid Build Coastguard Worker		// If Tidy_checks contains "-*", ignore all checks before "-*".
150*333d2b36SAndroid Build Coastguard Worker		localChecks := tidy.Properties.Tidy_checks
151*333d2b36SAndroid Build Coastguard Worker		ignoreGlobalChecks := false
152*333d2b36SAndroid Build Coastguard Worker		for n, check := range tidy.Properties.Tidy_checks {
153*333d2b36SAndroid Build Coastguard Worker			if check == "-*" {
154*333d2b36SAndroid Build Coastguard Worker				ignoreGlobalChecks = true
155*333d2b36SAndroid Build Coastguard Worker				localChecks = tidy.Properties.Tidy_checks[n:]
156*333d2b36SAndroid Build Coastguard Worker			}
157*333d2b36SAndroid Build Coastguard Worker		}
158*333d2b36SAndroid Build Coastguard Worker		if ignoreGlobalChecks {
159*333d2b36SAndroid Build Coastguard Worker			tidyChecks = "-checks=" + strings.Join(esc(ctx, "tidy_checks",
160*333d2b36SAndroid Build Coastguard Worker				config.ClangRewriteTidyChecks(localChecks)), ",")
161*333d2b36SAndroid Build Coastguard Worker		} else {
162*333d2b36SAndroid Build Coastguard Worker			tidyChecks = tidyChecks + "," + strings.Join(esc(ctx, "tidy_checks",
163*333d2b36SAndroid Build Coastguard Worker				config.ClangRewriteTidyChecks(localChecks)), ",")
164*333d2b36SAndroid Build Coastguard Worker		}
165*333d2b36SAndroid Build Coastguard Worker	}
166*333d2b36SAndroid Build Coastguard Worker	tidyChecks = tidyChecks + config.TidyGlobalNoChecks()
167*333d2b36SAndroid Build Coastguard Worker	if ctx.Windows() {
168*333d2b36SAndroid Build Coastguard Worker		// https://b.corp.google.com/issues/120614316
169*333d2b36SAndroid Build Coastguard Worker		// mingw32 has cert-dcl16-c warning in NO_ERROR,
170*333d2b36SAndroid Build Coastguard Worker		// which is used in many Android files.
171*333d2b36SAndroid Build Coastguard Worker		tidyChecks += ",-cert-dcl16-c"
172*333d2b36SAndroid Build Coastguard Worker	}
173*333d2b36SAndroid Build Coastguard Worker
174*333d2b36SAndroid Build Coastguard Worker	flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
175*333d2b36SAndroid Build Coastguard Worker
176*333d2b36SAndroid Build Coastguard Worker	// Embedding -warnings-as-errors in tidy_flags is error-prone.
177*333d2b36SAndroid Build Coastguard Worker	// It should be replaced with the tidy_checks_as_errors list.
178*333d2b36SAndroid Build Coastguard Worker	for i, s := range flags.TidyFlags {
179*333d2b36SAndroid Build Coastguard Worker		if strings.Contains(s, "-warnings-as-errors=") {
180*333d2b36SAndroid Build Coastguard Worker			if NoWarningsAsErrorsInTidyFlags {
181*333d2b36SAndroid Build Coastguard Worker				ctx.PropertyErrorf("tidy_flags", "should not contain "+s+"; use tidy_checks_as_errors instead.")
182*333d2b36SAndroid Build Coastguard Worker			} else {
183*333d2b36SAndroid Build Coastguard Worker				fmt.Printf("%s: warning: module %s's tidy_flags should not contain %s, which is replaced with -warnings-as-errors=-*; use tidy_checks_as_errors for your own as-error warnings instead.\n",
184*333d2b36SAndroid Build Coastguard Worker					ctx.BlueprintsFile(), ctx.ModuleName(), s)
185*333d2b36SAndroid Build Coastguard Worker				flags.TidyFlags[i] = "-warnings-as-errors=-*"
186*333d2b36SAndroid Build Coastguard Worker			}
187*333d2b36SAndroid Build Coastguard Worker			break // there is at most one -warnings-as-errors
188*333d2b36SAndroid Build Coastguard Worker		}
189*333d2b36SAndroid Build Coastguard Worker	}
190*333d2b36SAndroid Build Coastguard Worker	// Default clang-tidy flags does not contain -warning-as-errors.
191*333d2b36SAndroid Build Coastguard Worker	// If a module has tidy_checks_as_errors, add the list to -warnings-as-errors
192*333d2b36SAndroid Build Coastguard Worker	// and then append the TidyGlobalNoErrorChecks.
193*333d2b36SAndroid Build Coastguard Worker	if len(tidy.Properties.Tidy_checks_as_errors) > 0 {
194*333d2b36SAndroid Build Coastguard Worker		tidyChecksAsErrors := "-warnings-as-errors=" +
195*333d2b36SAndroid Build Coastguard Worker			strings.Join(esc(ctx, "tidy_checks_as_errors", tidy.Properties.Tidy_checks_as_errors), ",") +
196*333d2b36SAndroid Build Coastguard Worker			config.TidyGlobalNoErrorChecks()
197*333d2b36SAndroid Build Coastguard Worker		flags.TidyFlags = append(flags.TidyFlags, tidyChecksAsErrors)
198*333d2b36SAndroid Build Coastguard Worker	}
199*333d2b36SAndroid Build Coastguard Worker	return flags
200*333d2b36SAndroid Build Coastguard Worker}
201*333d2b36SAndroid Build Coastguard Worker
202*333d2b36SAndroid Build Coastguard Workerfunc init() {
203*333d2b36SAndroid Build Coastguard Worker	android.RegisterParallelSingletonType("tidy_phony_targets", TidyPhonySingleton)
204*333d2b36SAndroid Build Coastguard Worker}
205*333d2b36SAndroid Build Coastguard Worker
206*333d2b36SAndroid Build Coastguard Worker// This TidyPhonySingleton generates both tidy-* and obj-* phony targets for C/C++ files.
207*333d2b36SAndroid Build Coastguard Workerfunc TidyPhonySingleton() android.Singleton {
208*333d2b36SAndroid Build Coastguard Worker	return &tidyPhonySingleton{}
209*333d2b36SAndroid Build Coastguard Worker}
210*333d2b36SAndroid Build Coastguard Worker
211*333d2b36SAndroid Build Coastguard Workertype tidyPhonySingleton struct{}
212*333d2b36SAndroid Build Coastguard Worker
213*333d2b36SAndroid Build Coastguard Worker// Given a final module, add its tidy/obj phony targets to tidy/objModulesInDirGroup.
214*333d2b36SAndroid Build Coastguard Workerfunc collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Module,
215*333d2b36SAndroid Build Coastguard Worker	tidyModulesInDirGroup, objModulesInDirGroup map[string]map[string]android.Paths) {
216*333d2b36SAndroid Build Coastguard Worker	allObjFileGroups := make(map[string]android.Paths)     // variant group name => obj file Paths
217*333d2b36SAndroid Build Coastguard Worker	allTidyFileGroups := make(map[string]android.Paths)    // variant group name => tidy file Paths
218*333d2b36SAndroid Build Coastguard Worker	subsetObjFileGroups := make(map[string]android.Paths)  // subset group name => obj file Paths
219*333d2b36SAndroid Build Coastguard Worker	subsetTidyFileGroups := make(map[string]android.Paths) // subset group name => tidy file Paths
220*333d2b36SAndroid Build Coastguard Worker
221*333d2b36SAndroid Build Coastguard Worker	// (1) Collect all obj/tidy files into OS-specific groups.
222*333d2b36SAndroid Build Coastguard Worker	ctx.VisitAllModuleVariantProxies(module, func(variant android.ModuleProxy) {
223*333d2b36SAndroid Build Coastguard Worker		osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonModuleInfoKey).CompileTarget.Os.Name
224*333d2b36SAndroid Build Coastguard Worker		info := android.OtherModuleProviderOrDefault(ctx, variant, CcObjectInfoProvider)
225*333d2b36SAndroid Build Coastguard Worker		addToOSGroup(osName, info.objFiles, allObjFileGroups, subsetObjFileGroups)
226*333d2b36SAndroid Build Coastguard Worker		addToOSGroup(osName, info.tidyFiles, allTidyFileGroups, subsetTidyFileGroups)
227*333d2b36SAndroid Build Coastguard Worker	})
228*333d2b36SAndroid Build Coastguard Worker
229*333d2b36SAndroid Build Coastguard Worker	// (2) Add an all-OS group, with "" or "subset" name, to include all os-specific phony targets.
230*333d2b36SAndroid Build Coastguard Worker	addAllOSGroup(ctx, module, allObjFileGroups, "", "obj")
231*333d2b36SAndroid Build Coastguard Worker	addAllOSGroup(ctx, module, allTidyFileGroups, "", "tidy")
232*333d2b36SAndroid Build Coastguard Worker	addAllOSGroup(ctx, module, subsetObjFileGroups, "subset", "obj")
233*333d2b36SAndroid Build Coastguard Worker	addAllOSGroup(ctx, module, subsetTidyFileGroups, "subset", "tidy")
234*333d2b36SAndroid Build Coastguard Worker
235*333d2b36SAndroid Build Coastguard Worker	tidyTargetGroups := make(map[string]android.Path)
236*333d2b36SAndroid Build Coastguard Worker	objTargetGroups := make(map[string]android.Path)
237*333d2b36SAndroid Build Coastguard Worker	genObjTidyPhonyTargets(ctx, module, "obj", allObjFileGroups, objTargetGroups)
238*333d2b36SAndroid Build Coastguard Worker	genObjTidyPhonyTargets(ctx, module, "obj", subsetObjFileGroups, objTargetGroups)
239*333d2b36SAndroid Build Coastguard Worker	genObjTidyPhonyTargets(ctx, module, "tidy", allTidyFileGroups, tidyTargetGroups)
240*333d2b36SAndroid Build Coastguard Worker	genObjTidyPhonyTargets(ctx, module, "tidy", subsetTidyFileGroups, tidyTargetGroups)
241*333d2b36SAndroid Build Coastguard Worker
242*333d2b36SAndroid Build Coastguard Worker	moduleDir := ctx.ModuleDir(module)
243*333d2b36SAndroid Build Coastguard Worker	appendToModulesInDirGroup(tidyTargetGroups, moduleDir, tidyModulesInDirGroup)
244*333d2b36SAndroid Build Coastguard Worker	appendToModulesInDirGroup(objTargetGroups, moduleDir, objModulesInDirGroup)
245*333d2b36SAndroid Build Coastguard Worker}
246*333d2b36SAndroid Build Coastguard Worker
247*333d2b36SAndroid Build Coastguard Workerfunc (m *tidyPhonySingleton) GenerateBuildActions(ctx android.SingletonContext) {
248*333d2b36SAndroid Build Coastguard Worker	// For tidy-* directory phony targets, there are different variant groups.
249*333d2b36SAndroid Build Coastguard Worker	// tidyModulesInDirGroup[G][D] is for group G, directory D, with Paths
250*333d2b36SAndroid Build Coastguard Worker	// of all phony targets to be included into direct dependents of tidy-D_G.
251*333d2b36SAndroid Build Coastguard Worker	tidyModulesInDirGroup := make(map[string]map[string]android.Paths)
252*333d2b36SAndroid Build Coastguard Worker	// Also for obj-* directory phony targets.
253*333d2b36SAndroid Build Coastguard Worker	objModulesInDirGroup := make(map[string]map[string]android.Paths)
254*333d2b36SAndroid Build Coastguard Worker
255*333d2b36SAndroid Build Coastguard Worker	// Collect tidy/obj targets from the 'final' modules.
256*333d2b36SAndroid Build Coastguard Worker	ctx.VisitAllModules(func(module android.Module) {
257*333d2b36SAndroid Build Coastguard Worker		if ctx.IsFinalModule(module) {
258*333d2b36SAndroid Build Coastguard Worker			collectTidyObjModuleTargets(ctx, module, tidyModulesInDirGroup, objModulesInDirGroup)
259*333d2b36SAndroid Build Coastguard Worker		}
260*333d2b36SAndroid Build Coastguard Worker	})
261*333d2b36SAndroid Build Coastguard Worker
262*333d2b36SAndroid Build Coastguard Worker	suffix := ""
263*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().KatiEnabled() {
264*333d2b36SAndroid Build Coastguard Worker		suffix = "-soong"
265*333d2b36SAndroid Build Coastguard Worker	}
266*333d2b36SAndroid Build Coastguard Worker	generateObjTidyPhonyTargets(ctx, suffix, "obj", objModulesInDirGroup)
267*333d2b36SAndroid Build Coastguard Worker	generateObjTidyPhonyTargets(ctx, suffix, "tidy", tidyModulesInDirGroup)
268*333d2b36SAndroid Build Coastguard Worker}
269*333d2b36SAndroid Build Coastguard Worker
270*333d2b36SAndroid Build Coastguard Worker// The name for an obj/tidy module variant group phony target is Name_group-obj/tidy,
271*333d2b36SAndroid Build Coastguard Workerfunc objTidyModuleGroupName(module android.Module, group string, suffix string) string {
272*333d2b36SAndroid Build Coastguard Worker	if group == "" {
273*333d2b36SAndroid Build Coastguard Worker		return module.Name() + "-" + suffix
274*333d2b36SAndroid Build Coastguard Worker	}
275*333d2b36SAndroid Build Coastguard Worker	return module.Name() + "_" + group + "-" + suffix
276*333d2b36SAndroid Build Coastguard Worker}
277*333d2b36SAndroid Build Coastguard Worker
278*333d2b36SAndroid Build Coastguard Worker// Generate obj-* or tidy-* phony targets.
279*333d2b36SAndroid Build Coastguard Workerfunc generateObjTidyPhonyTargets(ctx android.SingletonContext, suffix string, prefix string, objTidyModulesInDirGroup map[string]map[string]android.Paths) {
280*333d2b36SAndroid Build Coastguard Worker	// For each variant group, create a <prefix>-<directory>_group target that
281*333d2b36SAndroid Build Coastguard Worker	// depends on all subdirectories and modules in the directory.
282*333d2b36SAndroid Build Coastguard Worker	for group, modulesInDir := range objTidyModulesInDirGroup {
283*333d2b36SAndroid Build Coastguard Worker		groupSuffix := ""
284*333d2b36SAndroid Build Coastguard Worker		if group != "" {
285*333d2b36SAndroid Build Coastguard Worker			groupSuffix = "_" + group
286*333d2b36SAndroid Build Coastguard Worker		}
287*333d2b36SAndroid Build Coastguard Worker		mmTarget := func(dir string) string {
288*333d2b36SAndroid Build Coastguard Worker			return prefix + "-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) + groupSuffix
289*333d2b36SAndroid Build Coastguard Worker		}
290*333d2b36SAndroid Build Coastguard Worker		dirs, topDirs := android.AddAncestors(ctx, modulesInDir, mmTarget)
291*333d2b36SAndroid Build Coastguard Worker		// Create a <prefix>-soong_group target that depends on all <prefix>-dir_group of top level dirs.
292*333d2b36SAndroid Build Coastguard Worker		var topDirPaths android.Paths
293*333d2b36SAndroid Build Coastguard Worker		for _, dir := range topDirs {
294*333d2b36SAndroid Build Coastguard Worker			topDirPaths = append(topDirPaths, android.PathForPhony(ctx, mmTarget(dir)))
295*333d2b36SAndroid Build Coastguard Worker		}
296*333d2b36SAndroid Build Coastguard Worker		ctx.Phony(prefix+suffix+groupSuffix, topDirPaths...)
297*333d2b36SAndroid Build Coastguard Worker		// Create a <prefix>-dir_group target that depends on all targets in modulesInDir[dir]
298*333d2b36SAndroid Build Coastguard Worker		for _, dir := range dirs {
299*333d2b36SAndroid Build Coastguard Worker			if dir != "." && dir != "" {
300*333d2b36SAndroid Build Coastguard Worker				ctx.Phony(mmTarget(dir), modulesInDir[dir]...)
301*333d2b36SAndroid Build Coastguard Worker			}
302*333d2b36SAndroid Build Coastguard Worker		}
303*333d2b36SAndroid Build Coastguard Worker	}
304*333d2b36SAndroid Build Coastguard Worker}
305*333d2b36SAndroid Build Coastguard Worker
306*333d2b36SAndroid Build Coastguard Worker// Append (obj|tidy)TargetGroups[group] into (obj|tidy)ModulesInDirGroups[group][moduleDir].
307*333d2b36SAndroid Build Coastguard Workerfunc appendToModulesInDirGroup(targetGroups map[string]android.Path, moduleDir string, modulesInDirGroup map[string]map[string]android.Paths) {
308*333d2b36SAndroid Build Coastguard Worker	for group, phonyPath := range targetGroups {
309*333d2b36SAndroid Build Coastguard Worker		if _, found := modulesInDirGroup[group]; !found {
310*333d2b36SAndroid Build Coastguard Worker			modulesInDirGroup[group] = make(map[string]android.Paths)
311*333d2b36SAndroid Build Coastguard Worker		}
312*333d2b36SAndroid Build Coastguard Worker		modulesInDirGroup[group][moduleDir] = append(modulesInDirGroup[group][moduleDir], phonyPath)
313*333d2b36SAndroid Build Coastguard Worker	}
314*333d2b36SAndroid Build Coastguard Worker}
315*333d2b36SAndroid Build Coastguard Worker
316*333d2b36SAndroid Build Coastguard Worker// Add given files to the OS group and subset group.
317*333d2b36SAndroid Build Coastguard Workerfunc addToOSGroup(osName string, files android.Paths, allGroups, subsetGroups map[string]android.Paths) {
318*333d2b36SAndroid Build Coastguard Worker	if len(files) > 0 {
319*333d2b36SAndroid Build Coastguard Worker		subsetName := osName + "_subset"
320*333d2b36SAndroid Build Coastguard Worker		allGroups[osName] = append(allGroups[osName], files...)
321*333d2b36SAndroid Build Coastguard Worker		// Now include only the first variant in the subsetGroups.
322*333d2b36SAndroid Build Coastguard Worker		// If clang and clang-tidy get faster, we might include more variants.
323*333d2b36SAndroid Build Coastguard Worker		if _, found := subsetGroups[subsetName]; !found {
324*333d2b36SAndroid Build Coastguard Worker			subsetGroups[subsetName] = files
325*333d2b36SAndroid Build Coastguard Worker		}
326*333d2b36SAndroid Build Coastguard Worker	}
327*333d2b36SAndroid Build Coastguard Worker}
328*333d2b36SAndroid Build Coastguard Worker
329*333d2b36SAndroid Build Coastguard Worker// Add an all-OS group, with groupName, to include all os-specific phony targets.
330*333d2b36SAndroid Build Coastguard Workerfunc addAllOSGroup(ctx android.SingletonContext, module android.Module, phonyTargetGroups map[string]android.Paths, groupName string, objTidyName string) {
331*333d2b36SAndroid Build Coastguard Worker	if len(phonyTargetGroups) > 0 {
332*333d2b36SAndroid Build Coastguard Worker		var targets android.Paths
333*333d2b36SAndroid Build Coastguard Worker		for group, _ := range phonyTargetGroups {
334*333d2b36SAndroid Build Coastguard Worker			targets = append(targets, android.PathForPhony(ctx, objTidyModuleGroupName(module, group, objTidyName)))
335*333d2b36SAndroid Build Coastguard Worker		}
336*333d2b36SAndroid Build Coastguard Worker		phonyTargetGroups[groupName] = targets
337*333d2b36SAndroid Build Coastguard Worker	}
338*333d2b36SAndroid Build Coastguard Worker}
339*333d2b36SAndroid Build Coastguard Worker
340*333d2b36SAndroid Build Coastguard Worker// Create one phony targets for each group and add them to the targetGroups.
341*333d2b36SAndroid Build Coastguard Workerfunc genObjTidyPhonyTargets(ctx android.SingletonContext, module android.Module, objTidyName string, fileGroups map[string]android.Paths, targetGroups map[string]android.Path) {
342*333d2b36SAndroid Build Coastguard Worker	for group, files := range fileGroups {
343*333d2b36SAndroid Build Coastguard Worker		groupName := objTidyModuleGroupName(module, group, objTidyName)
344*333d2b36SAndroid Build Coastguard Worker		ctx.Phony(groupName, files...)
345*333d2b36SAndroid Build Coastguard Worker		targetGroups[group] = android.PathForPhony(ctx, groupName)
346*333d2b36SAndroid Build Coastguard Worker	}
347*333d2b36SAndroid Build Coastguard Worker}
348