Skip to content

Commit d293818

Browse files
committed
Merge remote-tracking branch 'origin/main' into vplan-materialize-buildvector-for-vpreplicate-recipes
2 parents 66dea83 + d9971be commit d293818

File tree

296 files changed

+17252
-3872
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

296 files changed

+17252
-3872
lines changed

clang-tools-extra/clang-include-fixer/IncludeFixer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class Action : public clang::ASTFrontendAction {
5353

5454
Compiler->createSema(getTranslationUnitKind(), CompletionConsumer);
5555
SemaSource->setCompilerInstance(Compiler);
56-
Compiler->getSema().addExternalSource(SemaSource.get());
56+
Compiler->getSema().addExternalSource(SemaSource);
5757

5858
clang::ParseAST(Compiler->getSema(), Compiler->getFrontendOpts().ShowStats,
5959
Compiler->getFrontendOpts().SkipFunctionBodies);

clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ bool isCompleteAndHasNoZeroValue(const EnumDecl *D) {
2222
const EnumDecl *Definition = D->getDefinition();
2323
return Definition && Definition->isComplete() &&
2424
!Definition->enumerators().empty() &&
25-
std::none_of(Definition->enumerator_begin(),
26-
Definition->enumerator_end(),
27-
[](const EnumConstantDecl *Value) {
28-
return Value->getInitVal().isZero();
29-
});
25+
llvm::none_of(Definition->enumerators(),
26+
[](const EnumConstantDecl *Value) {
27+
return Value->getInitVal().isZero();
28+
});
3029
}
3130

3231
AST_MATCHER(EnumDecl, isCompleteAndHasNoZeroValue) {

clang-tools-extra/clang-tidy/bugprone/NonZeroEnumToBoolConversionCheck.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ namespace {
2222
AST_MATCHER(EnumDecl, isCompleteAndHasNoZeroValue) {
2323
const EnumDecl *Definition = Node.getDefinition();
2424
return Definition && Node.isComplete() &&
25-
std::none_of(Definition->enumerator_begin(),
26-
Definition->enumerator_end(),
27-
[](const EnumConstantDecl *Value) {
28-
return Value->getInitVal().isZero();
29-
});
25+
llvm::none_of(Definition->enumerators(),
26+
[](const EnumConstantDecl *Value) {
27+
return Value->getInitVal().isZero();
28+
});
3029
}
3130

3231
} // namespace

clang-tools-extra/clang-tidy/tool/run-clang-tidy.py

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
import time
5050
import traceback
5151
from types import ModuleType
52-
from typing import Any, Awaitable, Callable, List, Optional, TypeVar
52+
from typing import Any, Awaitable, Callable, Dict, List, Optional, Tuple, TypeVar
5353

5454

5555
yaml: Optional[ModuleType] = None
@@ -105,6 +105,7 @@ def get_tidy_invocation(
105105
warnings_as_errors: Optional[str],
106106
exclude_header_filter: Optional[str],
107107
allow_no_checks: bool,
108+
store_check_profile: Optional[str],
108109
) -> List[str]:
109110
"""Gets a command line for clang-tidy."""
110111
start = [clang_tidy_binary]
@@ -147,6 +148,9 @@ def get_tidy_invocation(
147148
start.append(f"--warnings-as-errors={warnings_as_errors}")
148149
if allow_no_checks:
149150
start.append("--allow-no-checks")
151+
if store_check_profile:
152+
start.append("--enable-check-profile")
153+
start.append(f"--store-check-profile={store_check_profile}")
150154
if f:
151155
start.append(f)
152156
return start
@@ -178,6 +182,124 @@ def merge_replacement_files(tmpdir: str, mergefile: str) -> None:
178182
open(mergefile, "w").close()
179183

180184

185+
def aggregate_profiles(profile_dir: str) -> Dict[str, float]:
186+
"""Aggregate timing data from multiple profile JSON files"""
187+
aggregated: Dict[str, float] = {}
188+
189+
for profile_file in glob.iglob(os.path.join(profile_dir, "*.json")):
190+
try:
191+
with open(profile_file, "r", encoding="utf-8") as f:
192+
data = json.load(f)
193+
profile_data: Dict[str, float] = data.get("profile", {})
194+
195+
for key, value in profile_data.items():
196+
if key.startswith("time.clang-tidy."):
197+
if key in aggregated:
198+
aggregated[key] += value
199+
else:
200+
aggregated[key] = value
201+
except (json.JSONDecodeError, KeyError, IOError) as e:
202+
print(f"Error: invalid json file {profile_file}: {e}", file=sys.stderr)
203+
continue
204+
205+
return aggregated
206+
207+
208+
def print_profile_data(aggregated_data: Dict[str, float]) -> None:
209+
"""Print aggregated checks profile data in the same format as clang-tidy"""
210+
if not aggregated_data:
211+
return
212+
213+
# Extract checker names and their timing data
214+
checkers: Dict[str, Dict[str, float]] = {}
215+
for key, value in aggregated_data.items():
216+
parts = key.split(".")
217+
if len(parts) >= 4 and parts[0] == "time" and parts[1] == "clang-tidy":
218+
checker_name = ".".join(
219+
parts[2:-1]
220+
) # Everything between "clang-tidy" and the timing type
221+
timing_type = parts[-1] # wall, user, or sys
222+
223+
if checker_name not in checkers:
224+
checkers[checker_name] = {"wall": 0.0, "user": 0.0, "sys": 0.0}
225+
226+
checkers[checker_name][timing_type] = value
227+
228+
if not checkers:
229+
return
230+
231+
total_user = sum(data["user"] for data in checkers.values())
232+
total_sys = sum(data["sys"] for data in checkers.values())
233+
total_wall = sum(data["wall"] for data in checkers.values())
234+
235+
sorted_checkers: List[Tuple[str, Dict[str, float]]] = sorted(
236+
checkers.items(), key=lambda x: x[1]["user"] + x[1]["sys"], reverse=True
237+
)
238+
239+
def print_stderr(*args, **kwargs) -> None:
240+
print(*args, file=sys.stderr, **kwargs)
241+
242+
print_stderr(
243+
"===-------------------------------------------------------------------------==="
244+
)
245+
print_stderr(" clang-tidy checks profiling")
246+
print_stderr(
247+
"===-------------------------------------------------------------------------==="
248+
)
249+
print_stderr(
250+
f" Total Execution Time: {total_user + total_sys:.4f} seconds ({total_wall:.4f} wall clock)\n"
251+
)
252+
253+
# Calculate field widths based on the Total line which has the largest values
254+
total_combined = total_user + total_sys
255+
user_width = len(f"{total_user:.4f}")
256+
sys_width = len(f"{total_sys:.4f}")
257+
combined_width = len(f"{total_combined:.4f}")
258+
wall_width = len(f"{total_wall:.4f}")
259+
260+
# Header with proper alignment
261+
additional_width = 9 # for " (100.0%)"
262+
user_header = "---User Time---".center(user_width + additional_width)
263+
sys_header = "--System Time--".center(sys_width + additional_width)
264+
combined_header = "--User+System--".center(combined_width + additional_width)
265+
wall_header = "---Wall Time---".center(wall_width + additional_width)
266+
267+
print_stderr(
268+
f" {user_header} {sys_header} {combined_header} {wall_header} --- Name ---"
269+
)
270+
271+
for checker_name, data in sorted_checkers:
272+
user_time = data["user"]
273+
sys_time = data["sys"]
274+
wall_time = data["wall"]
275+
combined_time = user_time + sys_time
276+
277+
user_percent = (user_time / total_user * 100) if total_user > 0 else 0
278+
sys_percent = (sys_time / total_sys * 100) if total_sys > 0 else 0
279+
combined_percent = (
280+
(combined_time / total_combined * 100) if total_combined > 0 else 0
281+
)
282+
wall_percent = (wall_time / total_wall * 100) if total_wall > 0 else 0
283+
284+
user_str = f"{user_time:{user_width}.4f} ({user_percent:5.1f}%)"
285+
sys_str = f"{sys_time:{sys_width}.4f} ({sys_percent:5.1f}%)"
286+
combined_str = f"{combined_time:{combined_width}.4f} ({combined_percent:5.1f}%)"
287+
wall_str = f"{wall_time:{wall_width}.4f} ({wall_percent:5.1f}%)"
288+
289+
print_stderr(
290+
f" {user_str} {sys_str} {combined_str} {wall_str} {checker_name}"
291+
)
292+
293+
user_total_str = f"{total_user:{user_width}.4f} (100.0%)"
294+
sys_total_str = f"{total_sys:{sys_width}.4f} (100.0%)"
295+
combined_total_str = f"{total_combined:{combined_width}.4f} (100.0%)"
296+
wall_total_str = f"{total_wall:{wall_width}.4f} (100.0%)"
297+
298+
print_stderr(
299+
f" {user_total_str} {sys_total_str} {combined_total_str} {wall_total_str} Total"
300+
)
301+
302+
181303
def find_binary(arg: str, name: str, build_path: str) -> str:
182304
"""Get the path for a binary or exit"""
183305
if arg:
@@ -240,6 +362,7 @@ async def run_tidy(
240362
clang_tidy_binary: str,
241363
tmpdir: str,
242364
build_path: str,
365+
store_check_profile: Optional[str],
243366
) -> ClangTidyResult:
244367
"""
245368
Runs clang-tidy on a single file and returns the result.
@@ -263,6 +386,7 @@ async def run_tidy(
263386
args.warnings_as_errors,
264387
args.exclude_header_filter,
265388
args.allow_no_checks,
389+
store_check_profile,
266390
)
267391

268392
try:
@@ -447,6 +571,11 @@ async def main() -> None:
447571
action="store_true",
448572
help="Allow empty enabled checks.",
449573
)
574+
parser.add_argument(
575+
"-enable-check-profile",
576+
action="store_true",
577+
help="Enable per-check timing profiles, and print a report",
578+
)
450579
args = parser.parse_args()
451580

452581
db_path = "compile_commands.json"
@@ -489,6 +618,10 @@ async def main() -> None:
489618
export_fixes_dir = tempfile.mkdtemp()
490619
delete_fixes_dir = True
491620

621+
profile_dir: Optional[str] = None
622+
if args.enable_check_profile:
623+
profile_dir = tempfile.mkdtemp()
624+
492625
try:
493626
invocation = get_tidy_invocation(
494627
None,
@@ -509,6 +642,7 @@ async def main() -> None:
509642
args.warnings_as_errors,
510643
args.exclude_header_filter,
511644
args.allow_no_checks,
645+
None, # No profiling for the list-checks invocation
512646
)
513647
invocation.append("-list-checks")
514648
invocation.append("-")
@@ -567,6 +701,7 @@ async def main() -> None:
567701
clang_tidy_binary,
568702
export_fixes_dir,
569703
build_path,
704+
profile_dir,
570705
)
571706
)
572707
for f in files
@@ -593,8 +728,19 @@ async def main() -> None:
593728
if delete_fixes_dir:
594729
assert export_fixes_dir
595730
shutil.rmtree(export_fixes_dir)
731+
if profile_dir:
732+
shutil.rmtree(profile_dir)
596733
return
597734

735+
if args.enable_check_profile and profile_dir:
736+
# Ensure all clang-tidy stdout is flushed before printing profiling
737+
sys.stdout.flush()
738+
aggregated_data = aggregate_profiles(profile_dir)
739+
if aggregated_data:
740+
print_profile_data(aggregated_data)
741+
else:
742+
print("No profiling data found.")
743+
598744
if combine_fixes:
599745
print(f"Writing fixes to {args.export_fixes} ...")
600746
try:
@@ -618,6 +764,8 @@ async def main() -> None:
618764
if delete_fixes_dir:
619765
assert export_fixes_dir
620766
shutil.rmtree(export_fixes_dir)
767+
if profile_dir:
768+
shutil.rmtree(profile_dir)
621769
sys.exit(returncode)
622770

623771

clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,10 @@ RenamerClangTidyCheck::addUsage(
432432
if (FixLocation.isInvalid())
433433
return {NamingCheckFailures.end(), false};
434434

435+
// Skip if in system system header
436+
if (SourceMgr.isInSystemHeader(FixLocation))
437+
return {NamingCheckFailures.end(), false};
438+
435439
auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId);
436440
NamingCheckFailure &Failure = EmplaceResult.first->second;
437441

@@ -455,6 +459,9 @@ RenamerClangTidyCheck::addUsage(
455459
void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl,
456460
SourceRange UsageRange,
457461
const SourceManager &SourceMgr) {
462+
if (SourceMgr.isInSystemHeader(Decl->getLocation()))
463+
return;
464+
458465
if (hasNoName(Decl))
459466
return;
460467

clang-tools-extra/clangd/HeaderSourceSwitch.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,24 @@ namespace clangd {
2020

2121
std::optional<Path> getCorrespondingHeaderOrSource(
2222
PathRef OriginalFile, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
23-
llvm::StringRef SourceExtensions[] = {".cpp", ".c", ".cc", ".cxx",
24-
".c++", ".m", ".mm"};
25-
llvm::StringRef HeaderExtensions[] = {".h", ".hh", ".hpp", ".hxx",
26-
".inc", ".cppm", ".ccm", ".cxxm",
27-
".c++m", ".ixx"};
23+
static constexpr llvm::StringRef SourceExtensions[] = {
24+
".cpp", ".c", ".cc", ".cxx", ".c++", ".m", ".mm"};
25+
static constexpr llvm::StringRef HeaderExtensions[] = {
26+
".h", ".hh", ".hpp", ".hxx", ".inc",
27+
".cppm", ".ccm", ".cxxm", ".c++m", ".ixx"};
2828

2929
llvm::StringRef PathExt = llvm::sys::path::extension(OriginalFile);
3030

3131
// Lookup in a list of known extensions.
32-
bool IsSource = llvm::any_of(SourceExtensions, [&PathExt](PathRef SourceExt) {
33-
return SourceExt.equals_insensitive(PathExt);
34-
});
32+
const bool IsSource =
33+
llvm::any_of(SourceExtensions, [&PathExt](PathRef SourceExt) {
34+
return SourceExt.equals_insensitive(PathExt);
35+
});
3536

36-
bool IsHeader = llvm::any_of(HeaderExtensions, [&PathExt](PathRef HeaderExt) {
37-
return HeaderExt.equals_insensitive(PathExt);
38-
});
37+
const bool IsHeader =
38+
llvm::any_of(HeaderExtensions, [&PathExt](PathRef HeaderExt) {
39+
return HeaderExt.equals_insensitive(PathExt);
40+
});
3941

4042
// We can only switch between the known extensions.
4143
if (!IsSource && !IsHeader)
@@ -94,7 +96,7 @@ std::optional<Path> getCorrespondingHeaderOrSource(PathRef OriginalFile,
9496
//
9597
// For each symbol in the original file, we get its target ___location (decl or
9698
// def) from the index, then award that target file.
97-
bool IsHeader = isHeaderFile(OriginalFile, AST.getLangOpts());
99+
const bool IsHeader = isHeaderFile(OriginalFile, AST.getLangOpts());
98100
Index->lookup(Request, [&](const Symbol &Sym) {
99101
if (IsHeader)
100102
AwardTarget(Sym.Definition.FileURI);

clang-tools-extra/clangd/XRefs.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2287,7 +2287,8 @@ prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath) {
22872287
Decl->getKind() != Decl::Kind::FunctionTemplate &&
22882288
!(Decl->getKind() == Decl::Kind::Var &&
22892289
!cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2290-
Decl->getKind() != Decl::Kind::Field)
2290+
Decl->getKind() != Decl::Kind::Field &&
2291+
Decl->getKind() != Decl::Kind::EnumConstant)
22912292
continue;
22922293
if (auto CHI = declToCallHierarchyItem(*Decl, AST.tuPath()))
22932294
Result.emplace_back(std::move(*CHI));

clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,35 @@ TEST(CallHierarchy, HierarchyOnVar) {
633633
iFromRanges(Source.range("Callee")))));
634634
}
635635

636+
TEST(CallHierarchy, HierarchyOnEnumConstant) {
637+
// Tests that the call hierarchy works on enum constants.
638+
Annotations Source(R"cpp(
639+
enum class Coin { heads$Heads^ , tai$Tails^ls };
640+
void caller() {
641+
Coin::$CallerH[[heads]];
642+
Coin::$CallerT[[tails]];
643+
}
644+
)cpp");
645+
TestTU TU = TestTU::withCode(Source.code());
646+
auto AST = TU.build();
647+
auto Index = TU.index();
648+
649+
std::vector<CallHierarchyItem> Items =
650+
prepareCallHierarchy(AST, Source.point("Heads"), testPath(TU.Filename));
651+
ASSERT_THAT(Items, ElementsAre(withName("heads")));
652+
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
653+
ASSERT_THAT(IncomingLevel1,
654+
ElementsAre(AllOf(from(withName("caller")),
655+
iFromRanges(Source.range("CallerH")))));
656+
Items =
657+
prepareCallHierarchy(AST, Source.point("Tails"), testPath(TU.Filename));
658+
ASSERT_THAT(Items, ElementsAre(withName("tails")));
659+
IncomingLevel1 = incomingCalls(Items[0], Index.get());
660+
ASSERT_THAT(IncomingLevel1,
661+
ElementsAre(AllOf(from(withName("caller")),
662+
iFromRanges(Source.range("CallerT")))));
663+
}
664+
636665
TEST(CallHierarchy, CallInDifferentFileThanCaller) {
637666
Annotations Header(R"cpp(
638667
#define WALDO void caller() {

0 commit comments

Comments
 (0)