aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra')
-rw-r--r--clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp53
-rw-r--r--clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp18
-rw-r--r--clang-tools-extra/clang-doc/JSONGenerator.cpp4
-rw-r--r--clang-tools-extra/clang-doc/Serialize.cpp9
-rw-r--r--clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp3
-rw-r--r--clang-tools-extra/clang-reorder-fields/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-reorder-fields/Designator.cpp219
-rw-r--r--clang-tools-extra/clang-reorder-fields/Designator.h164
-rw-r--r--clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp331
-rw-r--r--clang-tools-extra/clang-tidy/.clang-format2
-rw-r--r--clang-tools-extra/clang-tidy/.clang-tidy1
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidy.cpp16
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidy.h3
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationAdditionCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationComparisonCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationConversionCastCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationFactoryFloatCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationFactoryScaleCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationSubtractionCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/TimeComparisonCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.h3
-rwxr-xr-xclang-tools-extra/clang-tidy/add_new_check.py12
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp6
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h6
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp22
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp11
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp18
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp19
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp6
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp8
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp17
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/MultiLevelImplicitPointerConversionCheck.h2
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp6
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp10
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h2
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp8
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp11
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp13
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp32
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.cpp262
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.h56
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp27
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h7
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp5
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCallsCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsDeclarationsCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp23
-rw-r--r--clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp31
-rw-r--r--clang-tools-extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp9
-rw-r--r--clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/misc/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp11
-rw-r--r--clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp14
-rw-r--r--clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp17
-rw-r--r--clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp150
-rw-r--r--clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h43
-rw-r--r--clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp13
-rw-r--r--clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp8
-rw-r--r--clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp10
-rw-r--r--clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp10
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp11
-rw-r--r--clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp8
-rw-r--r--clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp53
-rw-r--r--clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h4
-rw-r--r--clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp16
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp15
-rw-r--r--clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp72
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp22
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp22
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp53
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp45
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp93
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp16
-rw-r--r--clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp7
-rw-r--r--clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp12
-rw-r--r--clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp8
-rw-r--r--clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp37
-rw-r--r--clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp10
-rw-r--r--clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp11
-rw-r--r--clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp84
-rw-r--r--clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.h3
-rw-r--r--clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp6
-rw-r--r--clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp24
-rw-r--r--clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp14
-rw-r--r--clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp42
-rw-r--r--clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp19
-rw-r--r--clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp17
-rw-r--r--clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp26
-rw-r--r--clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp7
-rw-r--r--clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h3
-rw-r--r--clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp19
-rw-r--r--clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp6
-rw-r--r--clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp15
-rwxr-xr-xclang-tools-extra/clang-tidy/tool/clang-tidy-diff.py8
-rwxr-xr-xclang-tools-extra/clang-tidy/tool/run-clang-tidy.py2
-rw-r--r--clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp1
-rw-r--r--clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp5
-rw-r--r--clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/utils/Matchers.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp37
-rw-r--r--clang-tools-extra/clang-tidy/utils/TypeTraits.cpp12
-rw-r--r--clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h3
-rw-r--r--clang-tools-extra/clangd/AST.cpp96
-rw-r--r--clang-tools-extra/clangd/AST.h3
-rw-r--r--clang-tools-extra/clangd/CMakeLists.txt5
-rw-r--r--clang-tools-extra/clangd/CodeComplete.cpp22
-rw-r--r--clang-tools-extra/clangd/CodeCompletionStrings.cpp64
-rw-r--r--clang-tools-extra/clangd/Config.h3
-rw-r--r--clang-tools-extra/clangd/ConfigCompile.cpp6
-rw-r--r--clang-tools-extra/clangd/ConfigFragment.h2
-rw-r--r--clang-tools-extra/clangd/ConfigYAML.cpp4
-rw-r--r--clang-tools-extra/clangd/DumpAST.cpp41
-rw-r--r--clang-tools-extra/clangd/FindTarget.cpp123
-rw-r--r--clang-tools-extra/clangd/GlobalCompilationDatabase.cpp4
-rw-r--r--clang-tools-extra/clangd/Hover.cpp368
-rw-r--r--clang-tools-extra/clangd/Hover.h21
-rw-r--r--clang-tools-extra/clangd/IncludeFixer.cpp52
-rw-r--r--clang-tools-extra/clangd/InlayHints.cpp28
-rw-r--r--clang-tools-extra/clangd/ModulesBuilder.cpp17
-rw-r--r--clang-tools-extra/clangd/Protocol.cpp3
-rw-r--r--clang-tools-extra/clangd/Quality.cpp3
-rw-r--r--clang-tools-extra/clangd/ScanningProjectModules.cpp11
-rw-r--r--clang-tools-extra/clangd/Selection.cpp17
-rw-r--r--clang-tools-extra/clangd/SemanticHighlighting.cpp15
-rw-r--r--clang-tools-extra/clangd/SemanticSelection.cpp37
-rw-r--r--clang-tools-extra/clangd/SymbolDocumentation.cpp386
-rw-r--r--clang-tools-extra/clangd/SymbolDocumentation.h211
-rw-r--r--clang-tools-extra/clangd/XRefs.cpp15
-rw-r--r--clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp121
-rw-r--r--clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp9
-rw-r--r--clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp6
-rw-r--r--clang-tools-extra/clangd/support/DirectiveTree.cpp57
-rw-r--r--clang-tools-extra/clangd/support/DirectiveTree.h4
-rw-r--r--clang-tools-extra/clangd/support/Markup.cpp7
-rw-r--r--clang-tools-extra/clangd/test/modules_no_cdb.test66
-rw-r--r--clang-tools-extra/clangd/unittests/ASTTests.cpp7
-rw-r--r--clang-tools-extra/clangd/unittests/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp192
-rw-r--r--clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp4
-rw-r--r--clang-tools-extra/clangd/unittests/DumpASTTests.cpp15
-rw-r--r--clang-tools-extra/clangd/unittests/FindTargetTests.cpp10
-rw-r--r--clang-tools-extra/clangd/unittests/HoverTests.cpp635
-rw-r--r--clang-tools-extra/clangd/unittests/InlayHintTests.cpp9
-rw-r--r--clang-tools-extra/clangd/unittests/QualityTests.cpp14
-rw-r--r--clang-tools-extra/clangd/unittests/RenameTests.cpp23
-rw-r--r--clang-tools-extra/clangd/unittests/SelectionTests.cpp4
-rw-r--r--clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp39
-rw-r--r--clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp215
-rw-r--r--clang-tools-extra/clangd/unittests/support/MarkupTests.cpp8
-rw-r--r--clang-tools-extra/docs/ReleaseNotes.rst59
-rw-r--r--clang-tools-extra/docs/ReleaseNotesTemplate.txt122
-rw-r--r--clang-tools-extra/docs/clang-change-namespace.rst314
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.rst64
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-pointer-arithmetic.rst8
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/list.rst2
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/misc/override-with-different-visibility.rst87
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst23
-rw-r--r--clang-tools-extra/docs/clang-tidy/index.rst122
-rw-r--r--clang-tools-extra/docs/index.rst1
-rw-r--r--clang-tools-extra/include-cleaner/lib/WalkAST.cpp28
-rw-r--r--clang-tools-extra/test/clang-doc/basic-project.mustache.test8
-rw-r--r--clang-tools-extra/test/clang-doc/json/class-requires.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/class-specialization.cpp4
-rw-r--r--clang-tools-extra/test/clang-doc/json/class-template.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/class.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/compound-constraints.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/concept.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/function-requires.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/function-specifiers.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/method-template.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/namespace.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/json/nested-namespace.cpp4
-rw-r--r--clang-tools-extra/test/clang-doc/long-name.cpp14
-rw-r--r--clang-tools-extra/test/clang-doc/mustache-index.cpp2
-rw-r--r--clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp2
-rw-r--r--clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.c12
-rw-r--r--clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp4
-rw-r--r--clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c31
-rw-r--r--clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.cpp24
-rw-r--r--clang-tools-extra/test/clang-reorder-fields/IdiomaticZeroInitializer.c14
-rw-r--r--clang-tools-extra/test/clang-reorder-fields/InitializerListExcessElements.c15
-rwxr-xr-xclang-tools-extra/test/clang-tidy/check_clang_tidy.py23
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/stdfloat18
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/system-other.h2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry-custom-macro.c4
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry.c4
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-macro-crash.c10
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp1
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-relatedness.c27
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters.c28
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-in-initialization-strlen.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-before-safe.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-safe.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-stdc-want-lib-ext1-not-a-literal.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-strlen.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-undef-stdc-want-lib-ext1.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.c7
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.c4
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp11
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c12
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp6
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/cert/uppercase-literal-suffix-integer.cpp29
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/prefer-member-initializer.cpp13
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.cpp341
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-pointer-arithmetic.cpp16
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/google/objc-function-naming.m2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-different-visibility/test-system-header.h14
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-ignore.cpp60
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-options.cpp75
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility.cpp289
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/misc/unconventional-assign-operator.cpp8
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.c8
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize/make-shared.cpp2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-GH153649.cpp15
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp68
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp22
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/bitint-no-crash.c3
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp90
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c6
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-c23.c120
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-cxx23.cpp264
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-float16.cpp51
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point-opencl-half.cpp9
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point.cpp36
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-hexadecimal-floating-point.cpp30
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-custom-list.cpp15
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-ms.cpp17
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer.cpp60
-rw-r--r--clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp2
-rw-r--r--clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp5
-rw-r--r--clang-tools-extra/test/clang-tidy/infrastructure/quiet-flag.cpp26
-rw-r--r--clang-tools-extra/test/clang-tidy/infrastructure/system-headers.cpp4
268 files changed, 7034 insertions, 1557 deletions
diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
index 3e367ab..471ca45 100644
--- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
@@ -31,24 +31,9 @@ llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
return Splitted;
}
-SourceLocation startLocationForType(TypeLoc TLoc) {
- // For elaborated types (e.g. `struct a::A`) we want the portion after the
- // `struct` but including the namespace qualifier, `a::`.
- if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
- NestedNameSpecifierLoc NestedNameSpecifier =
- TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
- if (NestedNameSpecifier.getNestedNameSpecifier())
- return NestedNameSpecifier.getBeginLoc();
- TLoc = TLoc.getNextTypeLoc();
- }
- return TLoc.getBeginLoc();
-}
-
SourceLocation endLocationForType(TypeLoc TLoc) {
- // Dig past any namespace or keyword qualifications.
- while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
- TLoc.getTypeLocClass() == TypeLoc::Qualified)
- TLoc = TLoc.getNextTypeLoc();
+ if (auto QTL = TLoc.getAs<QualifiedTypeLoc>())
+ TLoc = QTL.getUnqualifiedLoc();
// The location for template specializations (e.g. Foo<int>) includes the
// templated types in its location range. We want to restrict this to just
@@ -550,8 +535,8 @@ void ChangeNamespaceTool::run(
Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
"nested_specifier_loc")) {
SourceLocation Start = Specifier->getBeginLoc();
- SourceLocation End = endLocationForType(Specifier->getTypeLoc());
- fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
+ SourceLocation End = endLocationForType(Specifier->castAsTypeLoc());
+ fixTypeLoc(Result, Start, End, Specifier->castAsTypeLoc());
} else if (const auto *BaseInitializer =
Result.Nodes.getNodeAs<CXXCtorInitializer>(
"base_initializer")) {
@@ -562,19 +547,16 @@ void ChangeNamespaceTool::run(
// filtered by matchers in some cases, e.g. the type is templated. We should
// handle the record type qualifier instead.
TypeLoc Loc = *TLoc;
- while (Loc.getTypeLocClass() == TypeLoc::Qualified)
- Loc = Loc.getNextTypeLoc();
- if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
- NestedNameSpecifierLoc NestedNameSpecifier =
- Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
- // FIXME: avoid changing injected class names.
- if (auto *NNS = NestedNameSpecifier.getNestedNameSpecifier()) {
- const Type *SpecifierType = NNS->getAsType();
- if (SpecifierType && SpecifierType->isRecordType())
- return;
- }
- }
- fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
+ if (auto QTL = Loc.getAs<QualifiedTypeLoc>())
+ Loc = QTL.getUnqualifiedLoc();
+ // FIXME: avoid changing injected class names.
+ if (NestedNameSpecifier NestedNameSpecifier =
+ Loc.getPrefix().getNestedNameSpecifier();
+ NestedNameSpecifier.getKind() == NestedNameSpecifier::Kind::Type &&
+ NestedNameSpecifier.getAsType()->isRecordType())
+ return;
+ fixTypeLoc(Result, Loc.getNonElaboratedBeginLoc(), endLocationForType(Loc),
+ Loc);
} else if (const auto *VarRef =
Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
@@ -588,10 +570,9 @@ void ChangeNamespaceTool::run(
} else if (const auto *EnumConstRef =
Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
// Do not rename the reference if it is already scoped by the EnumDecl name.
- if (EnumConstRef->hasQualifier() &&
- EnumConstRef->getQualifier()->getKind() ==
- NestedNameSpecifier::SpecifierKind::TypeSpec &&
- EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
+ if (NestedNameSpecifier Qualifier = EnumConstRef->getQualifier();
+ Qualifier.getKind() == NestedNameSpecifier::Kind::Type &&
+ Qualifier.getAsType()->isEnumeralType())
return;
const auto *EnumConstDecl =
Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index a64cb5e..1ab40aa 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -144,17 +144,22 @@ Error MustacheHTMLGenerator::generateDocs(
} else
return JSONGenerator.takeError();
}
+ SmallString<128> JSONPath;
+ sys::path::native(RootDir.str() + "/json", JSONPath);
StringMap<json::Value> JSONFileMap;
{
llvm::TimeTraceScope TS("Iterate JSON files");
std::error_code EC;
- sys::fs::directory_iterator JSONIter(RootDir, EC);
+ sys::fs::directory_iterator JSONIter(JSONPath, EC);
std::vector<json::Value> JSONFiles;
JSONFiles.reserve(Infos.size());
if (EC)
return createStringError("Failed to create directory iterator.");
+ SmallString<128> HTMLDirPath(RootDir.str() + "/html/");
+ if (auto EC = sys::fs::create_directories(HTMLDirPath))
+ return createFileError(HTMLDirPath, EC);
while (JSONIter != sys::fs::directory_iterator()) {
if (EC)
return createFileError("Failed to iterate: " + JSONIter->path(), EC);
@@ -177,14 +182,15 @@ Error MustacheHTMLGenerator::generateDocs(
return Parsed.takeError();
std::error_code FileErr;
- SmallString<16> HTMLPath(Path.begin(), Path.end());
- sys::path::replace_extension(HTMLPath, "html");
- raw_fd_ostream InfoOS(HTMLPath, FileErr, sys::fs::OF_None);
+ SmallString<128> HTMLFilePath(HTMLDirPath);
+ sys::path::append(HTMLFilePath, sys::path::filename(Path));
+ sys::path::replace_extension(HTMLFilePath, "html");
+ raw_fd_ostream InfoOS(HTMLFilePath, FileErr, sys::fs::OF_None);
if (FileErr)
return createFileOpenError(Path, FileErr);
- if (Error Err = generateDocForJSON(*Parsed, sys::path::stem(HTMLPath),
- HTMLPath, InfoOS, CDCtx))
+ if (Error Err = generateDocForJSON(*Parsed, sys::path::stem(HTMLFilePath),
+ HTMLFilePath, InfoOS, CDCtx))
return Err;
JSONIter.increment(EC);
}
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 599b381..26794a5 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -600,7 +600,9 @@ Error JSONGenerator::generateDocs(
Info *Info = Group.getValue().get();
SmallString<128> Path;
- sys::path::native(RootDir, Path);
+ auto RootDirStr = RootDir.str() + "/json";
+ StringRef JSONDir = StringRef(RootDirStr);
+ sys::path::native(JSONDir, Path);
if (!CreatedDirs.contains(Path)) {
if (std::error_code Err = sys::fs::create_directories(Path);
Err != std::error_code())
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index de73f68..dd7cd0b 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -778,7 +778,9 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
Mangler->mangleCXXVTable(CXXD, MangledStream);
else
MangledStream << D->getNameAsString();
- if (MangledName.size() > 255)
+ // A 250 length limit was chosen since 255 is a common limit across
+ // different filesystems, with a 5 character buffer for file extensions.
+ if (MangledName.size() > 250)
// File creation fails if the mangled name is too long, so default to the
// USR. We should look for a better check since filesystems differ in
// maximum filename length
@@ -901,9 +903,8 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
if (!D->isThisDeclarationADefinition())
return;
for (const CXXBaseSpecifier &B : D->bases()) {
- if (const RecordType *Ty = B.getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *Base =
- cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
+ if (const auto *Base = B.getType()->getAsCXXRecordDecl()) {
+ if (Base->isCompleteDefinition()) {
// Initialized without USR and name, this will be set in the following
// if-else stmt.
BaseRecordInfo BI(
diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp
index bb48883..1f30d27 100644
--- a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp
+++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp
@@ -216,8 +216,7 @@ void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) {
// Uses of most types: just look at what the typeLoc refers to.
MatchFinder->addMatcher(
typeLoc(isExpansionInMainFile(),
- loc(qualType(allOf(unless(elaboratedType()),
- hasDeclaration(Types.bind("use")))))),
+ loc(qualType(hasDeclaration(Types.bind("use"))))),
this);
// Uses of typedefs: these are often transparent to hasDeclaration, so we need
// to handle them explicitly.
diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
index 2fdeb65d..dec0287 100644
--- a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
+++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangReorderFields STATIC
+ Designator.cpp
ReorderFieldsAction.cpp
DEPENDS
diff --git a/clang-tools-extra/clang-reorder-fields/Designator.cpp b/clang-tools-extra/clang-reorder-fields/Designator.cpp
new file mode 100644
index 0000000..d36a080
--- /dev/null
+++ b/clang-tools-extra/clang-reorder-fields/Designator.cpp
@@ -0,0 +1,219 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the definition of the Designator and Designators utility
+/// classes.
+///
+//===----------------------------------------------------------------------===//
+
+#include "Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace reorder_fields {
+
+void Designator::advanceToNextField() {
+ assert(!isFinished() && "Iterator is already finished");
+ switch (Tag) {
+ case STRUCT:
+ if (StructIt.Record->isUnion()) {
+ // Union always finishes on first increment.
+ StructIt.Field = StructIt.Record->field_end();
+ Type = QualType();
+ break;
+ }
+ ++StructIt.Field;
+ if (StructIt.Field != StructIt.Record->field_end()) {
+ Type = StructIt.Field->getType();
+ } else {
+ Type = QualType();
+ }
+ break;
+ case ARRAY:
+ ++ArrayIt.Index;
+ break;
+ case ARRAY_RANGE:
+ ArrayIt.Index = ArrayRangeIt.End + 1;
+ ArrayIt.Size = ArrayRangeIt.Size;
+ Tag = ARRAY;
+ break;
+ }
+}
+
+bool Designator::isFinished() {
+ switch (Tag) {
+ case STRUCT:
+ return StructIt.Field == StructIt.Record->field_end();
+ case ARRAY:
+ return ArrayIt.Index == ArrayIt.Size;
+ case ARRAY_RANGE:
+ return ArrayRangeIt.End == ArrayRangeIt.Size;
+ }
+ return false;
+}
+
+Designators::Designators(const Expr *Init, const InitListExpr *ILE,
+ const ASTContext *Context)
+ : Context(Context) {
+ if (ILE->getType()->isArrayType()) {
+ const ConstantArrayType *CAT =
+ Context->getAsConstantArrayType(ILE->getType());
+ // Only constant size arrays are supported.
+ if (!CAT) {
+ DesignatorList.clear();
+ return;
+ }
+ DesignatorList.push_back(
+ {CAT->getElementType(), 0, CAT->getSize().getZExtValue()});
+ } else {
+ const RecordDecl *DesignatorRD = ILE->getType()->getAsRecordDecl();
+ DesignatorList.push_back({DesignatorRD->field_begin()->getType(),
+ DesignatorRD->field_begin(), DesignatorRD});
+ }
+
+ // If the designator list is empty at this point, then there must be excess
+ // elements in the initializer list. They are not currently supported.
+ if (DesignatorList.empty())
+ return;
+
+ if (!enterImplicitInitLists(Init))
+ DesignatorList.clear();
+}
+
+Designators::Designators(const DesignatedInitExpr *DIE, const InitListExpr *ILE,
+ const ASTContext *Context)
+ : Context(Context) {
+ for (const auto &D : DIE->designators()) {
+ if (D.isFieldDesignator()) {
+ RecordDecl *DesignatorRecord = D.getFieldDecl()->getParent();
+ for (auto FieldIt = DesignatorRecord->field_begin();
+ FieldIt != DesignatorRecord->field_end(); ++FieldIt) {
+ if (*FieldIt == D.getFieldDecl()) {
+ DesignatorList.push_back(
+ {FieldIt->getType(), FieldIt, DesignatorRecord});
+ break;
+ }
+ }
+ } else {
+ const QualType CurrentType = DesignatorList.empty()
+ ? ILE->getType()
+ : DesignatorList.back().getType();
+ const ConstantArrayType *CAT =
+ Context->getAsConstantArrayType(CurrentType);
+ if (!CAT) {
+ // Non-constant-sized arrays are not supported.
+ DesignatorList.clear();
+ return;
+ }
+ if (D.isArrayDesignator()) {
+ DesignatorList.push_back({CAT->getElementType(),
+ DIE->getArrayIndex(D)
+ ->EvaluateKnownConstInt(*Context)
+ .getZExtValue(),
+ CAT->getSize().getZExtValue()});
+ } else if (D.isArrayRangeDesignator()) {
+ DesignatorList.push_back({CAT->getElementType(),
+ DIE->getArrayRangeStart(D)
+ ->EvaluateKnownConstInt(*Context)
+ .getZExtValue(),
+ DIE->getArrayRangeEnd(D)
+ ->EvaluateKnownConstInt(*Context)
+ .getZExtValue(),
+ CAT->getSize().getZExtValue()});
+ } else {
+ llvm_unreachable("Unexpected designator kind");
+ }
+ }
+ }
+}
+
+bool Designators::advanceToNextField(const Expr *Init) {
+ // Remove all designators that refer to the last field of a struct or final
+ // element of the array.
+ while (!DesignatorList.empty()) {
+ auto &CurrentDesignator = DesignatorList.back();
+ CurrentDesignator.advanceToNextField();
+ if (CurrentDesignator.isFinished()) {
+ DesignatorList.pop_back();
+ continue;
+ }
+ break;
+ }
+
+ // If the designator list is empty at this point, then there must be excess
+ // elements in the initializer list. They are not currently supported.
+ if (DesignatorList.empty())
+ return false;
+
+ if (!enterImplicitInitLists(Init)) {
+ DesignatorList.clear();
+ return false;
+ }
+
+ return true;
+}
+
+bool Designators::enterImplicitInitLists(const Expr *Init) {
+ // Check for missing braces by comparing the type of the last designator and
+ // type of Init.
+ while (true) {
+ const QualType T = DesignatorList.back().getType();
+ // If the types match, there are no missing braces.
+ if (Init->getType() == T)
+ break;
+
+ // If the current type is a struct, then get its first field.
+ if (T->isRecordType()) {
+ DesignatorList.push_back({T->getAsRecordDecl()->field_begin()->getType(),
+ T->getAsRecordDecl()->field_begin(),
+ T->getAsRecordDecl()});
+ continue;
+ }
+ // If the current type is an array, then get its first element.
+ if (T->isArrayType()) {
+ DesignatorList.push_back(
+ {Context->getAsArrayType(T)->getElementType(), 0,
+ Context->getAsConstantArrayType(T)->getSize().getZExtValue()});
+ continue;
+ }
+
+ // The initializer doesn't match the expected type. The initializer list is
+ // invalid.
+ return false;
+ }
+
+ return true;
+}
+
+std::string Designators::toString() const {
+ if (DesignatorList.empty())
+ return "";
+ std::string Designator;
+ llvm::raw_string_ostream OS(Designator);
+ for (auto &I : DesignatorList) {
+ switch (I.getTag()) {
+ case Designator::STRUCT:
+ OS << '.' << I.getStructIter()->getName();
+ break;
+ case Designator::ARRAY:
+ OS << '[' << I.getArrayIndex() << ']';
+ break;
+ case Designator::ARRAY_RANGE:
+ OS << '[' << I.getArrayRangeStart() << "..." << I.getArrayRangeEnd()
+ << ']';
+ }
+ }
+ OS << " = ";
+ return Designator;
+}
+
+} // namespace reorder_fields
+} // namespace clang
diff --git a/clang-tools-extra/clang-reorder-fields/Designator.h b/clang-tools-extra/clang-reorder-fields/Designator.h
new file mode 100644
index 0000000..859be28
--- /dev/null
+++ b/clang-tools-extra/clang-reorder-fields/Designator.h
@@ -0,0 +1,164 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.h -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declarations of the Designator and Designators
+/// utility classes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace reorder_fields {
+
+/// Represents a part of a designation in a C99/C++20 designated initializer. It
+/// is a tagged union of different kinds of designators: struct, array and array
+/// range. Holds enough information to be able to advance to the next field and
+/// to know when all fields have been iterated through.
+class Designator {
+public:
+ enum Kind { STRUCT, ARRAY, ARRAY_RANGE };
+
+ Designator(const QualType Type, RecordDecl::field_iterator Field,
+ const RecordDecl *RD)
+ : Tag(STRUCT), Type(Type), StructIt({Field, RD}) {}
+
+ Designator(const QualType Type, uint64_t Idx, uint64_t Size)
+ : Tag(ARRAY), Type(Type), ArrayIt({Idx, Size}) {}
+
+ Designator(const QualType Type, uint64_t Start, uint64_t End, uint64_t Size)
+ : Tag(ARRAY_RANGE), Type(Type), ArrayRangeIt({Start, End, Size}) {}
+
+ /// Moves the iterator to the next element.
+ void advanceToNextField();
+
+ /// Checks if the iterator has iterated through all elements.
+ bool isFinished();
+
+ Kind getTag() const { return Tag; }
+ QualType getType() const { return Type; }
+
+ const RecordDecl::field_iterator getStructIter() const {
+ assert(Tag == STRUCT && "Must be a field designator");
+ return StructIt.Field;
+ }
+
+ const RecordDecl *getStructDecl() const {
+ assert(Tag == STRUCT && "Must be a field designator");
+ return StructIt.Record;
+ }
+
+ uint64_t getArrayIndex() const {
+ assert(Tag == ARRAY && "Must be an array designator");
+ return ArrayIt.Index;
+ }
+
+ uint64_t getArrayRangeStart() const {
+ assert(Tag == ARRAY_RANGE && "Must be an array range designator");
+ return ArrayRangeIt.Start;
+ }
+
+ uint64_t getArrayRangeEnd() const {
+ assert(Tag == ARRAY_RANGE && "Must be an array range designator");
+ return ArrayRangeIt.End;
+ }
+
+ uint64_t getArraySize() const {
+ assert((Tag == ARRAY || Tag == ARRAY_RANGE) &&
+ "Must be an array or range designator");
+ if (Tag == ARRAY)
+ return ArrayIt.Size;
+ return ArrayRangeIt.Size;
+ }
+
+private:
+ /// Type of the designator.
+ Kind Tag;
+
+ /// Type of the designated entry. For arrays this is the type of the element.
+ QualType Type;
+
+ /// Field designator has the iterator to the field and the record the field
+ /// is declared in.
+ struct StructIter {
+ RecordDecl::field_iterator Field;
+ const RecordDecl *Record;
+ };
+
+ /// Array designator has an index and size of the array.
+ struct ArrayIter {
+ uint64_t Index;
+ uint64_t Size;
+ };
+
+ /// Array range designator has a start and end index and size of the array.
+ struct ArrayRangeIter {
+ uint64_t Start;
+ uint64_t End;
+ uint64_t Size;
+ };
+
+ union {
+ StructIter StructIt;
+ ArrayIter ArrayIt;
+ ArrayRangeIter ArrayRangeIt;
+ };
+};
+
+/// List of designators.
+class Designators {
+public:
+ /// Initialize to the first member of the struct/array. Enters implicit
+ /// initializer lists until a type that matches Init is found.
+ Designators(const Expr *Init, const InitListExpr *ILE,
+ const ASTContext *Context);
+
+ /// Initialize to the designators of the given expression.
+ Designators(const DesignatedInitExpr *DIE, const InitListExpr *ILE,
+ const ASTContext *Context);
+
+ /// Return whether this designator list is valid.
+ bool isValid() const { return !DesignatorList.empty(); }
+
+ /// Moves the designators to the next initializer in the struct/array. If the
+ /// type of next initializer doesn't match the expected type then there are
+ /// omitted braces and we add new designators to reflect that.
+ bool advanceToNextField(const Expr *Init);
+
+ /// Gets a string representation from a list of designators. This string will
+ /// be inserted before an initializer expression to make it designated.
+ std::string toString() const;
+
+ size_t size() const { return DesignatorList.size(); }
+
+ SmallVector<Designator>::const_iterator begin() const {
+ return DesignatorList.begin();
+ }
+ SmallVector<Designator>::const_iterator end() const {
+ return DesignatorList.end();
+ }
+
+private:
+ /// Enters any implicit initializer lists until a type that matches the given
+ /// expression is found.
+ bool enterImplicitInitLists(const Expr *Init);
+
+ const ASTContext *Context;
+ SmallVector<Designator, 1> DesignatorList;
+};
+
+} // namespace reorder_fields
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ada9122..affa276 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ReorderFieldsAction.h"
+#include "Designator.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -25,6 +26,7 @@
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include <string>
namespace clang {
@@ -162,7 +164,91 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef<unsigned> NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+ NewFieldsPositions(NewFieldsOrder.size()) {
+ for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ /// Compares compatible designators according to the new struct order.
+ /// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0
+ /// if they are equal.
+ bool operator()(const Designator &Lhs, const Designator &Rhs) const;
+
+ /// Compares compatible designator lists according to the new struct order.
+ /// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0
+ /// if they are equal.
+ bool operator()(const Designators &Lhs, const Designators &Rhs) const;
+
+ const RecordDecl *Definition;
+ ArrayRef<unsigned> NewFieldsOrder;
+ SmallVector<unsigned, 4> NewFieldsPositions;
+};
+
+bool ReorderedStruct::operator()(const Designator &Lhs,
+ const Designator &Rhs) const {
+ switch (Lhs.getTag()) {
+ case Designator::STRUCT:
+ assert(Rhs.getTag() == Designator::STRUCT && "Incompatible designators");
+ assert(Lhs.getStructDecl() == Rhs.getStructDecl() &&
+ "Incompatible structs");
+ // Use the new layout for reordered struct.
+ if (Definition == Lhs.getStructDecl()) {
+ return NewFieldsPositions[Lhs.getStructIter()->getFieldIndex()] <
+ NewFieldsPositions[Rhs.getStructIter()->getFieldIndex()];
+ }
+ return Lhs.getStructIter()->getFieldIndex() <
+ Rhs.getStructIter()->getFieldIndex();
+ case Designator::ARRAY:
+ case Designator::ARRAY_RANGE:
+ // Array designators can be compared to array range designators.
+ assert((Rhs.getTag() == Designator::ARRAY ||
+ Rhs.getTag() == Designator::ARRAY_RANGE) &&
+ "Incompatible designators");
+ size_t LhsIdx = Lhs.getTag() == Designator::ARRAY
+ ? Lhs.getArrayIndex()
+ : Lhs.getArrayRangeStart();
+ size_t RhsIdx = Rhs.getTag() == Designator::ARRAY
+ ? Rhs.getArrayIndex()
+ : Rhs.getArrayRangeStart();
+ return LhsIdx < RhsIdx;
+ }
+ llvm_unreachable("Invalid designator tag");
+}
+
+bool ReorderedStruct::operator()(const Designators &Lhs,
+ const Designators &Rhs) const {
+ return std::lexicographical_compare(Lhs.begin(), Lhs.end(), Rhs.begin(),
+ Rhs.end(), *this);
+}
+
// FIXME: error-handling
+/// Replaces a range of source code by the specified text.
+static void
+addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,
+ std::map<std::string, tooling::Replacements> &Replacements) {
+ tooling::Replacement R(Context.getSourceManager(),
+ CharSourceRange::getTokenRange(Old), New,
+ Context.getLangOpts());
+ consumeError(Replacements[std::string(R.getFilePath())].add(R));
+}
+
+/// Replaces one range of source code by another and adds a prefix.
+static void
+addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,
+ const ASTContext &Context,
+ std::map<std::string, tooling::Replacements> &Replacements) {
+ std::string NewText =
+ (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+ Context.getSourceManager(),
+ Context.getLangOpts()))
+ .str();
+ addReplacement(Old, NewText, Context, Replacements);
+}
+
/// Replaces one range of source code by another.
static void
addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
@@ -174,10 +260,7 @@ addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
StringRef NewText =
Lexer::getSourceText(CharSourceRange::getTokenRange(New),
Context.getSourceManager(), Context.getLangOpts());
- tooling::Replacement R(Context.getSourceManager(),
- CharSourceRange::getTokenRange(Old), NewText,
- Context.getLangOpts());
- consumeError(Replacements[std::string(R.getFilePath())].add(R));
+ addReplacement(Old, NewText.str(), Context, Replacements);
}
/// Find all member fields used in the given init-list initializer expr
@@ -279,33 +362,33 @@ static SourceRange getFullFieldSourceRange(const FieldDecl &Field,
/// different accesses (public/protected/private) is not supported.
/// \returns true on success.
static bool reorderFieldsInDefinition(
- const RecordDecl *Definition, ArrayRef<unsigned> NewFieldsOrder,
- const ASTContext &Context,
+ const ReorderedStruct &RS, const ASTContext &Context,
std::map<std::string, tooling::Replacements> &Replacements) {
- assert(Definition && "Definition is null");
+ assert(RS.Definition && "Definition is null");
SmallVector<const FieldDecl *, 10> Fields;
- for (const auto *Field : Definition->fields())
+ for (const auto *Field : RS.Definition->fields())
Fields.push_back(Field);
// Check that the permutation of the fields doesn't change the accesses
- for (const auto *Field : Definition->fields()) {
+ for (const auto *Field : RS.Definition->fields()) {
const auto FieldIndex = Field->getFieldIndex();
- if (Field->getAccess() != Fields[NewFieldsOrder[FieldIndex]]->getAccess()) {
+ if (Field->getAccess() !=
+ Fields[RS.NewFieldsOrder[FieldIndex]]->getAccess()) {
llvm::errs() << "Currently reordering of fields with different accesses "
"is not supported\n";
return false;
}
}
- for (const auto *Field : Definition->fields()) {
+ for (const auto *Field : RS.Definition->fields()) {
const auto FieldIndex = Field->getFieldIndex();
- if (FieldIndex == NewFieldsOrder[FieldIndex])
+ if (FieldIndex == RS.NewFieldsOrder[FieldIndex])
continue;
- addReplacement(
- getFullFieldSourceRange(*Field, Context),
- getFullFieldSourceRange(*Fields[NewFieldsOrder[FieldIndex]], Context),
- Context, Replacements);
+ addReplacement(getFullFieldSourceRange(*Field, Context),
+ getFullFieldSourceRange(
+ *Fields[RS.NewFieldsOrder[FieldIndex]], Context),
+ Context, Replacements);
}
return true;
}
@@ -316,7 +399,7 @@ static bool reorderFieldsInDefinition(
/// fields. Thus, we need to ensure that we reorder just the initializers that
/// are present.
static void reorderFieldsInConstructor(
- const CXXConstructorDecl *CtorDecl, ArrayRef<unsigned> NewFieldsOrder,
+ const CXXConstructorDecl *CtorDecl, const ReorderedStruct &RS,
ASTContext &Context,
std::map<std::string, tooling::Replacements> &Replacements) {
assert(CtorDecl && "Constructor declaration is null");
@@ -328,10 +411,6 @@ static void reorderFieldsInConstructor(
// Thus this assert needs to be after the previous checks.
assert(CtorDecl->isThisDeclarationADefinition() && "Not a definition");
- SmallVector<unsigned, 10> NewFieldsPositions(NewFieldsOrder.size());
- for (unsigned i = 0, e = NewFieldsOrder.size(); i < e; ++i)
- NewFieldsPositions[NewFieldsOrder[i]] = i;
-
SmallVector<const CXXCtorInitializer *, 10> OldWrittenInitializersOrder;
SmallVector<const CXXCtorInitializer *, 10> NewWrittenInitializersOrder;
for (const auto *Initializer : CtorDecl->inits()) {
@@ -342,8 +421,8 @@ static void reorderFieldsInConstructor(
const FieldDecl *ThisM = Initializer->getMember();
const auto UsedMembers = findMembersUsedInInitExpr(Initializer, Context);
for (const FieldDecl *UM : UsedMembers) {
- if (NewFieldsPositions[UM->getFieldIndex()] >
- NewFieldsPositions[ThisM->getFieldIndex()]) {
+ if (RS.NewFieldsPositions[UM->getFieldIndex()] >
+ RS.NewFieldsPositions[ThisM->getFieldIndex()]) {
DiagnosticsEngine &DiagEngine = Context.getDiagnostics();
auto Description = ("reordering field " + UM->getName() + " after " +
ThisM->getName() + " makes " + UM->getName() +
@@ -361,8 +440,8 @@ static void reorderFieldsInConstructor(
auto ByFieldNewPosition = [&](const CXXCtorInitializer *LHS,
const CXXCtorInitializer *RHS) {
assert(LHS && RHS);
- return NewFieldsPositions[LHS->getMember()->getFieldIndex()] <
- NewFieldsPositions[RHS->getMember()->getFieldIndex()];
+ return RS.NewFieldsPositions[LHS->getMember()->getFieldIndex()] <
+ RS.NewFieldsPositions[RHS->getMember()->getFieldIndex()];
};
llvm::sort(NewWrittenInitializersOrder, ByFieldNewPosition);
assert(OldWrittenInitializersOrder.size() ==
@@ -374,35 +453,188 @@ static void reorderFieldsInConstructor(
Replacements);
}
+/// Replacement for broken InitListExpr::isExplicit function.
+/// FIXME: Remove when InitListExpr::isExplicit is fixed.
+static bool isImplicitILE(const InitListExpr *ILE, const ASTContext &Context) {
+ // The ILE is implicit if either:
+ // - The left brace loc of the ILE matches the start of first init expression
+ // (for non designated decls)
+ // - The right brace loc of the ILE matches the end of first init expression
+ // (for designated decls)
+ // The first init expression should be taken from the syntactic form, but
+ // since the ILE could be implicit, there might not be a syntactic form.
+ // For that reason we have to check against all init expressions.
+ for (const Expr *Init : ILE->inits()) {
+ if (ILE->getLBraceLoc() == Init->getBeginLoc() ||
+ ILE->getRBraceLoc() == Init->getEndLoc())
+ return true;
+ }
+ return false;
+}
+
+/// Finds the semantic form of the first explicit ancestor of the given
+/// initializer list including itself.
+static const InitListExpr *getExplicitILE(const InitListExpr *ILE,
+ ASTContext &Context) {
+ if (!isImplicitILE(ILE, Context))
+ return ILE;
+ const InitListExpr *TopLevelILE = ILE;
+ DynTypedNodeList Parents = Context.getParents(*TopLevelILE);
+ while (!Parents.empty() && Parents.begin()->get<InitListExpr>()) {
+ TopLevelILE = Parents.begin()->get<InitListExpr>();
+ Parents = Context.getParents(*TopLevelILE);
+ if (!isImplicitILE(TopLevelILE, Context))
+ break;
+ }
+ if (!TopLevelILE->isSemanticForm()) {
+ return TopLevelILE->getSemanticForm();
+ }
+ return TopLevelILE;
+}
+
+static void reportError(const Twine &Message, SourceLocation Loc,
+ const SourceManager &SM) {
+ if (Loc.isValid()) {
+ llvm::errs() << SM.getFilename(Loc) << ":" << SM.getPresumedLineNumber(Loc)
+ << ":" << SM.getPresumedColumnNumber(Loc) << ": ";
+ }
+ llvm::errs() << Message;
+}
+
/// Reorders initializers in the brace initialization of an aggregate.
///
/// At the moment partial initialization is not supported.
/// \returns true on success
static bool reorderFieldsInInitListExpr(
- const InitListExpr *InitListEx, ArrayRef<unsigned> NewFieldsOrder,
- const ASTContext &Context,
+ const InitListExpr *InitListEx, const ReorderedStruct &RS,
+ ASTContext &Context,
std::map<std::string, tooling::Replacements> &Replacements) {
assert(InitListEx && "Init list expression is null");
- // We care only about InitListExprs which originate from source code.
- // Implicit InitListExprs are created by the semantic analyzer.
- if (!InitListEx->isExplicit())
+ // Only process semantic forms of initializer lists.
+ if (!InitListEx->isSemanticForm()) {
return true;
- // The method InitListExpr::getSyntacticForm may return nullptr indicating
- // that the current initializer list also serves as its syntactic form.
- if (const auto *SyntacticForm = InitListEx->getSyntacticForm())
- InitListEx = SyntacticForm;
+ }
+
// If there are no initializers we do not need to change anything.
if (!InitListEx->getNumInits())
return true;
- if (InitListEx->getNumInits() != NewFieldsOrder.size()) {
- llvm::errs() << "Currently only full initialization is supported\n";
- return false;
+
+ // We care only about InitListExprs which originate from source code.
+ // Implicit InitListExprs are created by the semantic analyzer.
+ // We find the first parent InitListExpr that exists in source code and
+ // process it. This is necessary because of designated initializer lists and
+ // possible omitted braces.
+ InitListEx = getExplicitILE(InitListEx, Context);
+
+ // Find if there are any designated initializations or implicit values. If all
+ // initializers are present and none have designators then just reorder them
+ // normally. Otherwise, designators are added to all initializers and they are
+ // sorted in the new order.
+ bool HasImplicitInit = false;
+ bool HasDesignatedInit = false;
+ // The method InitListExpr::getSyntacticForm may return nullptr indicating
+ // that the current initializer list also serves as its syntactic form.
+ const InitListExpr *SyntacticInitListEx = InitListEx;
+ if (const InitListExpr *SynILE = InitListEx->getSyntacticForm()) {
+ // Do not rewrite zero initializers. This check is only valid for syntactic
+ // forms.
+ if (SynILE->isIdiomaticZeroInitializer(Context.getLangOpts()))
+ return true;
+
+ HasImplicitInit = InitListEx->getNumInits() != SynILE->getNumInits();
+ HasDesignatedInit = llvm::any_of(SynILE->inits(), [](const Expr *Init) {
+ return isa<DesignatedInitExpr>(Init);
+ });
+
+ SyntacticInitListEx = SynILE;
+ } else {
+ // If there is no syntactic form, there can be no designators. Instead,
+ // there might be implicit values.
+ HasImplicitInit =
+ (RS.NewFieldsOrder.size() != InitListEx->getNumInits()) ||
+ llvm::any_of(InitListEx->inits(), [&Context](const Expr *Init) {
+ return isa<ImplicitValueInitExpr>(Init) ||
+ (isa<InitListExpr>(Init) &&
+ isImplicitILE(dyn_cast<InitListExpr>(Init), Context));
+ });
+ }
+
+ if (HasImplicitInit || HasDesignatedInit) {
+ // Designators are only supported from C++20.
+ if (!HasDesignatedInit && Context.getLangOpts().CPlusPlus &&
+ !Context.getLangOpts().CPlusPlus20) {
+ reportError(
+ "Only full initialization without implicit values is supported\n",
+ InitListEx->getBeginLoc(), Context.getSourceManager());
+ return false;
+ }
+
+ // Handle case when some fields are designated. Some fields can be
+ // missing. Insert any missing designators and reorder the expressions
+ // according to the new order.
+ std::optional<Designators> CurrentDesignators;
+ // Remember each initializer expression along with its designators. They are
+ // sorted later to determine the correct order.
+ std::vector<std::pair<Designators, const Expr *>> Rewrites;
+ for (const Expr *Init : SyntacticInitListEx->inits()) {
+ if (const auto *DIE = dyn_cast_or_null<DesignatedInitExpr>(Init)) {
+ CurrentDesignators.emplace(DIE, SyntacticInitListEx, &Context);
+ if (!CurrentDesignators->isValid()) {
+ reportError("Unsupported initializer list\n", DIE->getBeginLoc(),
+ Context.getSourceManager());
+ return false;
+ }
+
+ // Use the child of the DesignatedInitExpr. This way designators are
+ // always replaced.
+ Rewrites.emplace_back(*CurrentDesignators, DIE->getInit());
+ } else {
+ // If designators are not initialized then initialize to the first
+ // field, otherwise move the next field.
+ if (!CurrentDesignators) {
+ CurrentDesignators.emplace(Init, SyntacticInitListEx, &Context);
+ if (!CurrentDesignators->isValid()) {
+ reportError("Unsupported initializer list\n",
+ InitListEx->getBeginLoc(), Context.getSourceManager());
+ return false;
+ }
+ } else if (!CurrentDesignators->advanceToNextField(Init)) {
+ reportError("Unsupported initializer list\n",
+ InitListEx->getBeginLoc(), Context.getSourceManager());
+ return false;
+ }
+
+ // Do not rewrite implicit values. They just had to be processed to
+ // find the correct designator.
+ if (!isa<ImplicitValueInitExpr>(Init))
+ Rewrites.emplace_back(*CurrentDesignators, Init);
+ }
+ }
+
+ // Sort the designators according to the new order.
+ llvm::stable_sort(Rewrites, [&RS](const auto &Lhs, const auto &Rhs) {
+ return RS(Lhs.first, Rhs.first);
+ });
+
+ for (unsigned i = 0, e = Rewrites.size(); i < e; ++i) {
+ addReplacement(SyntacticInitListEx->getInit(i)->getSourceRange(),
+ Rewrites[i].second->getSourceRange(),
+ Rewrites[i].first.toString(), Context, Replacements);
+ }
+ } else {
+ // Handle excess initializers by leaving them unchanged.
+ assert(SyntacticInitListEx->getNumInits() >= InitListEx->getNumInits());
+
+ // All field initializers are present and none have designators. They can be
+ // reordered normally.
+ for (unsigned i = 0, e = RS.NewFieldsOrder.size(); i < e; ++i) {
+ if (i != RS.NewFieldsOrder[i])
+ addReplacement(SyntacticInitListEx->getInit(i)->getSourceRange(),
+ SyntacticInitListEx->getInit(RS.NewFieldsOrder[i])
+ ->getSourceRange(),
+ Context, Replacements);
+ }
}
- for (unsigned i = 0, e = InitListEx->getNumInits(); i < e; ++i)
- if (i != NewFieldsOrder[i])
- addReplacement(InitListEx->getInit(i)->getSourceRange(),
- InitListEx->getInit(NewFieldsOrder[i])->getSourceRange(),
- Context, Replacements);
return true;
}
@@ -432,7 +664,9 @@ public:
getNewFieldsOrder(RD, DesiredFieldsOrder);
if (NewFieldsOrder.empty())
return;
- if (!reorderFieldsInDefinition(RD, NewFieldsOrder, Context, Replacements))
+ ReorderedStruct RS{RD, NewFieldsOrder};
+
+ if (!reorderFieldsInDefinition(RS, Context, Replacements))
return;
// CXXRD will be nullptr if C code (not C++) is being processed.
@@ -440,24 +674,25 @@ public:
if (CXXRD)
for (const auto *C : CXXRD->ctors())
if (const auto *D = dyn_cast<CXXConstructorDecl>(C->getDefinition()))
- reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D),
- NewFieldsOrder, Context, Replacements);
+ reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D), RS,
+ Context, Replacements);
// We only need to reorder init list expressions for
// plain C structs or C++ aggregate types.
// For other types the order of constructor parameters is used,
// which we don't change at the moment.
// Now (v0) partial initialization is not supported.
- if (!CXXRD || CXXRD->isAggregate())
+ if (!CXXRD || CXXRD->isAggregate()) {
for (auto Result :
match(initListExpr(hasType(equalsNode(RD))).bind("initListExpr"),
Context))
if (!reorderFieldsInInitListExpr(
- Result.getNodeAs<InitListExpr>("initListExpr"), NewFieldsOrder,
- Context, Replacements)) {
+ Result.getNodeAs<InitListExpr>("initListExpr"), RS, Context,
+ Replacements)) {
Replacements.clear();
return;
}
+ }
}
};
} // end anonymous namespace
diff --git a/clang-tools-extra/clang-tidy/.clang-format b/clang-tools-extra/clang-tidy/.clang-format
new file mode 100644
index 0000000..d18cf7c
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+QualifierAlignment: Left
diff --git a/clang-tools-extra/clang-tidy/.clang-tidy b/clang-tools-extra/clang-tidy/.clang-tidy
index 22a4bd7..0e33364 100644
--- a/clang-tools-extra/clang-tidy/.clang-tidy
+++ b/clang-tools-extra/clang-tidy/.clang-tidy
@@ -32,7 +32,6 @@ Checks: >
-readability-magic-numbers,
-readability-named-parameter,
-readability-qualified-auto,
- -readability-redundant-declaration,
-readability-simplify-boolean-expr,
-readability-static-definition-in-anonymous-namespace,
-readability-suspicious-call-argument,
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 4ae2864..2064c78 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -424,6 +424,10 @@ ClangTidyASTConsumerFactory::createASTConsumer(
FinderOptions.CheckProfiling.emplace(Profiling->Records);
}
+ // Avoid processing system headers, unless the user explicitly requests it
+ if (!Context.getOptions().SystemHeaders.value_or(false))
+ FinderOptions.IgnoreSystemHeaders = true;
+
std::unique_ptr<ast_matchers::MatchFinder> Finder(
new ast_matchers::MatchFinder(std::move(FinderOptions)));
@@ -540,7 +544,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
bool ApplyAnyFix, bool EnableCheckProfile,
- llvm::StringRef StoreCheckProfile) {
+ llvm::StringRef StoreCheckProfile, bool Quiet) {
ClangTool Tool(Compilations, InputFiles,
std::make_shared<PCHContainerOperations>(), BaseFS);
@@ -577,8 +581,9 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
class ActionFactory : public FrontendActionFactory {
public:
ActionFactory(ClangTidyContext &Context,
- IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS)
- : ConsumerFactory(Context, std::move(BaseFS)) {}
+ IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
+ bool Quiet)
+ : ConsumerFactory(Context, std::move(BaseFS)), Quiet(Quiet) {}
std::unique_ptr<FrontendAction> create() override {
return std::make_unique<Action>(&ConsumerFactory);
}
@@ -589,6 +594,8 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
DiagnosticConsumer *DiagConsumer) override {
// Explicitly ask to define __clang_analyzer__ macro.
Invocation->getPreprocessorOpts().SetUpStaticAnalyzer = true;
+ if (Quiet)
+ Invocation->getDiagnosticOpts().ShowCarets = false;
return FrontendActionFactory::runInvocation(
Invocation, Files, PCHContainerOps, DiagConsumer);
}
@@ -607,9 +614,10 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
};
ClangTidyASTConsumerFactory ConsumerFactory;
+ bool Quiet;
};
- ActionFactory Factory(Context, std::move(BaseFS));
+ ActionFactory Factory(Context, std::move(BaseFS), Quiet);
Tool.run(&Factory);
return DiagConsumer.take();
}
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h b/clang-tools-extra/clang-tidy/ClangTidy.h
index 454261b..d37d68e 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.h
+++ b/clang-tools-extra/clang-tidy/ClangTidy.h
@@ -94,7 +94,8 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
bool ApplyAnyFix, bool EnableCheckProfile = false,
- llvm::StringRef StoreCheckProfile = StringRef());
+ llvm::StringRef StoreCheckProfile = StringRef(),
+ bool Quiet = false);
/// Controls what kind of fixes clang-tidy is allowed to apply.
enum FixBehaviour {
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index f9d7597..fac6e04 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -533,7 +533,8 @@ void ClangTidyDiagnosticConsumer::forwardDiagnostic(const Diagnostic &Info) {
Builder << reinterpret_cast<const NamedDecl *>(Info.getRawArg(Index));
break;
case clang::DiagnosticsEngine::ak_nestednamespec:
- Builder << reinterpret_cast<NestedNameSpecifier *>(Info.getRawArg(Index));
+ Builder << NestedNameSpecifier::getFromVoidPointer(
+ reinterpret_cast<void *>(Info.getRawArg(Index)));
break;
case clang::DiagnosticsEngine::ak_declcontext:
Builder << reinterpret_cast<DeclContext *>(Info.getRawArg(Index));
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationAdditionCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationAdditionCheck.h
index 7f6b652..ac71f34 100644
--- a/clang-tools-extra/clang-tidy/abseil/DurationAdditionCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/DurationAdditionCheck.h
@@ -22,6 +22,9 @@ class DurationAdditionCheck : public ClangTidyCheck {
public:
DurationAdditionCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationComparisonCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationComparisonCheck.h
index d759e1d..65ab7a3 100644
--- a/clang-tools-extra/clang-tidy/abseil/DurationComparisonCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/DurationComparisonCheck.h
@@ -22,6 +22,9 @@ class DurationComparisonCheck : public ClangTidyCheck {
public:
DurationComparisonCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationConversionCastCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationConversionCastCheck.h
index fea9f70..a898ba0 100644
--- a/clang-tools-extra/clang-tidy/abseil/DurationConversionCastCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/DurationConversionCastCheck.h
@@ -22,6 +22,9 @@ class DurationConversionCastCheck : public ClangTidyCheck {
public:
DurationConversionCastCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationFactoryFloatCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationFactoryFloatCheck.h
index 6394b3f..e7c3985 100644
--- a/clang-tools-extra/clang-tidy/abseil/DurationFactoryFloatCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/DurationFactoryFloatCheck.h
@@ -24,6 +24,9 @@ class DurationFactoryFloatCheck : public ClangTidyCheck {
public:
DurationFactoryFloatCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationFactoryScaleCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationFactoryScaleCheck.h
index 40ffb30..f5f088c 100644
--- a/clang-tools-extra/clang-tidy/abseil/DurationFactoryScaleCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/DurationFactoryScaleCheck.h
@@ -24,6 +24,9 @@ class DurationFactoryScaleCheck : public ClangTidyCheck {
public:
DurationFactoryScaleCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationSubtractionCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationSubtractionCheck.h
index 17f7853..c865f2f 100644
--- a/clang-tools-extra/clang-tidy/abseil/DurationSubtractionCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/DurationSubtractionCheck.h
@@ -22,6 +22,9 @@ class DurationSubtractionCheck : public ClangTidyCheck {
public:
DurationSubtractionCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.h
index aa25c5f..fc9cf23 100644
--- a/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.h
@@ -22,6 +22,9 @@ class DurationUnnecessaryConversionCheck : public ClangTidyCheck {
public:
DurationUnnecessaryConversionCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/TimeComparisonCheck.h b/clang-tools-extra/clang-tidy/abseil/TimeComparisonCheck.h
index 0c647087..bf22977 100644
--- a/clang-tools-extra/clang-tidy/abseil/TimeComparisonCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/TimeComparisonCheck.h
@@ -22,6 +22,9 @@ class TimeComparisonCheck : public ClangTidyCheck {
public:
TimeComparisonCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.h b/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.h
index c947f6b..9e2ec1c 100644
--- a/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.h
+++ b/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.h
@@ -22,6 +22,9 @@ class TimeSubtractionCheck : public ClangTidyCheck {
public:
TimeSubtractionCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
diff --git a/clang-tools-extra/clang-tidy/add_new_check.py b/clang-tools-extra/clang-tidy/add_new_check.py
index e366f10..2b51a1d 100755
--- a/clang-tools-extra/clang-tidy/add_new_check.py
+++ b/clang-tools-extra/clang-tidy/add_new_check.py
@@ -89,13 +89,9 @@ def write_header(
+ check_name_camel.upper()
+ "_H"
)
- f.write("//===--- ")
- f.write(os.path.basename(filename))
- f.write(" - clang-tidy ")
- f.write("-" * max(0, 42 - len(os.path.basename(filename))))
- f.write("*- C++ -*-===//")
f.write(
"""
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -145,13 +141,9 @@ def write_implementation(
filename = os.path.join(module_path, check_name_camel) + ".cpp"
print("Creating %s..." % filename)
with io.open(filename, "w", encoding="utf8", newline="\n") as f:
- f.write("//===--- ")
- f.write(os.path.basename(filename))
- f.write(" - clang-tidy ")
- f.write("-" * max(0, 51 - len(os.path.basename(filename))))
- f.write("-===//")
f.write(
"""
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp
index 1bfe384..f188ae5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp
@@ -44,11 +44,11 @@ AST_MATCHER(CXXRecordDecl, correctHandleCaptureThisLambda) {
if (Node.hasSimpleMoveAssignment())
return false;
- for (CXXConstructorDecl const *C : Node.ctors()) {
+ for (const CXXConstructorDecl *C : Node.ctors()) {
if (C->isCopyOrMoveConstructor() && C->isDefaulted() && !C->isDeleted())
return false;
}
- for (CXXMethodDecl const *M : Node.methods()) {
+ for (const CXXMethodDecl *M : Node.methods()) {
if (M->isCopyAssignmentOperator())
llvm::errs() << M->isDeleted() << "\n";
if (M->isCopyAssignmentOperator() && M->isDefaulted() && !M->isDeleted())
diff --git a/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp
index 6565fa3..0625468 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp
@@ -43,7 +43,8 @@ static bool isDerivedClassBefriended(const CXXRecordDecl *CRTP,
return false;
}
- return FriendType->getType()->getAsCXXRecordDecl() == Derived;
+ return declaresSameEntity(FriendType->getType()->getAsCXXRecordDecl(),
+ Derived);
});
}
@@ -55,7 +56,8 @@ getDerivedParameter(const ClassTemplateSpecializationDecl *CRTP,
CRTP->getTemplateArgs().asArray(), [&](const TemplateArgument &Arg) {
++Idx;
return Arg.getKind() == TemplateArgument::Type &&
- Arg.getAsType()->getAsCXXRecordDecl() == Derived;
+ declaresSameEntity(Arg.getAsType()->getAsCXXRecordDecl(),
+ Derived);
});
return AnyOf ? CRTP->getSpecializedTemplate()
diff --git a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h
index 3044304..981e9b5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h
@@ -13,14 +13,16 @@
namespace clang::tidy::bugprone {
-/// Detect dangling references in value handlers like
-/// std::experimental::string_view.
+/// Detect dangling references in value handlers like std::string_view.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/dangling-handle.html
class DanglingHandleCheck : public ClangTidyCheck {
public:
DanglingHandleCheck(StringRef Name, ClangTidyContext *Context);
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
diff --git a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp
index a179d4bf..3c718f1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp
@@ -577,7 +577,7 @@ approximateImplicitConversion(const TheCheck &Check, QualType LType,
ImplicitConversionModellingMode ImplicitMode);
static inline bool isUselessSugar(const Type *T) {
- return isa<AttributedType, DecayedType, ElaboratedType, ParenType>(T);
+ return isa<AttributedType, DecayedType, ParenType>(T);
}
namespace {
@@ -997,7 +997,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
WorkType = QualType{ToBuiltin, FastQualifiersToApply};
}
- const auto *FromEnum = WorkType->getAs<EnumType>();
+ const auto *FromEnum = WorkType->getAsCanonical<EnumType>();
const auto *ToEnum = To->getAs<EnumType>();
if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) {
// Unscoped enumerations (or enumerations in C) convert to numerics.
@@ -1040,7 +1040,9 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
const auto *ToRecord = To->getAsCXXRecordDecl();
if (isDerivedToBase(FromRecord, ToRecord)) {
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n");
- WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply};
+ WorkType = QualType{
+ ToRecord->getASTContext().getCanonicalTagType(ToRecord)->getTypePtr(),
+ FastQualifiersToApply};
}
if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) {
@@ -1072,9 +1074,9 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
WorkType = To;
}
- if (WorkType == To) {
+ if (Ctx.hasSameType(WorkType, To)) {
LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n");
- return {WorkType};
+ return {Ctx.getCommonSugaredType(WorkType, To)};
}
LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n");
@@ -1219,7 +1221,7 @@ tryConversionOperators(const TheCheck &Check, const CXXRecordDecl *RD,
if (std::optional<UserDefinedConversionSelector::PreparedConversion>
SelectedConversion = ConversionSet()) {
- QualType RecordType{RD->getTypeForDecl(), 0};
+ CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
ConversionSequence Result{RecordType, ToType};
// The conversion from the operator call's return type to ToType was
@@ -1270,7 +1272,7 @@ tryConvertingConstructors(const TheCheck &Check, QualType FromType,
if (std::optional<UserDefinedConversionSelector::PreparedConversion>
SelectedConversion = ConversionSet()) {
- QualType RecordType{RD->getTypeForDecl(), 0};
+ CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
ConversionSequence Result{FromType, RecordType};
Result.AfterFirstStandard = SelectedConversion->Seq.AfterFirstStandard;
@@ -1573,6 +1575,10 @@ template <typename T, std::size_t N = SmallDataStructureSize>
using ParamToSmallSetMap =
llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
+template <typename T, std::size_t N = SmallDataStructureSize>
+using ParamToSmallPtrSetMap =
+ llvm::DenseMap<const ParmVarDecl *, llvm::SmallPtrSet<T, N>>;
+
/// Returns whether the sets mapped to the two elements in the map have at
/// least one element in common.
template <typename MapTy, typename ElemTy>
@@ -1697,7 +1703,7 @@ public:
/// Implements the heuristic that marks two parameters related if the same
/// member is accessed (referred to) inside the current function's body.
class AccessedSameMemberOf {
- ParamToSmallSetMap<const Decl *> AccessedMembers;
+ ParamToSmallPtrSetMap<const Decl *> AccessedMembers;
public:
void setup(const FunctionDecl *FD) {
diff --git a/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h b/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h
index af8c1e5..435c440 100644
--- a/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h
@@ -26,6 +26,9 @@ class FoldInitTypeCheck : public ClangTidyCheck {
public:
FoldInitTypeCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
index 75ef628..070ed04 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
@@ -69,10 +69,9 @@ void ForwardDeclarationNamespaceCheck::check(
// struct B { friend A; };
// \endcode
// `A` will not be marked as "referenced" in the AST.
- if (const TypeSourceInfo *Tsi = Decl->getFriendType()) {
- QualType Desugared = Tsi->getType().getDesugaredType(*Result.Context);
- FriendTypes.insert(Desugared.getTypePtr());
- }
+ if (const TypeSourceInfo *Tsi = Decl->getFriendType())
+ FriendTypes.insert(
+ Tsi->getType()->getCanonicalTypeUnqualified().getTypePtr());
}
}
@@ -119,7 +118,9 @@ void ForwardDeclarationNamespaceCheck::onEndOfTranslationUnit() {
if (CurDecl->hasDefinition() || CurDecl->isReferenced()) {
continue; // Skip forward declarations that are used/referenced.
}
- if (FriendTypes.contains(CurDecl->getTypeForDecl())) {
+ if (FriendTypes.contains(CurDecl->getASTContext()
+ .getCanonicalTagType(CurDecl)
+ ->getTypePtr())) {
continue; // Skip forward declarations referenced as friend.
}
if (CurDecl->getLocation().isMacroID() ||
diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
index 00e8f7e..10b747e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
@@ -33,21 +33,17 @@ AST_MATCHER(QualType, isEnableIf) {
BaseType = BaseType->getPointeeType().getTypePtr();
}
// Case: type parameter dependent (enable_if<is_integral<T>>).
- if (const auto *Dependent = BaseType->getAs<DependentNameType>()) {
- BaseType = Dependent->getQualifier()->getAsType();
- }
+ if (const auto *Dependent = BaseType->getAs<DependentNameType>())
+ BaseType = Dependent->getQualifier().getAsType();
if (!BaseType)
return false;
if (CheckTemplate(BaseType->getAs<TemplateSpecializationType>()))
return true; // Case: enable_if_t< >.
- if (const auto *Elaborated = BaseType->getAs<ElaboratedType>()) {
- if (const auto *Q = Elaborated->getQualifier())
- if (const auto *Qualifier = Q->getAsType()) {
- if (CheckTemplate(Qualifier->getAs<TemplateSpecializationType>())) {
- return true; // Case: enable_if< >::type.
- }
- }
- }
+ if (const auto *TT = BaseType->getAs<TypedefType>())
+ if (NestedNameSpecifier Q = TT->getQualifier();
+ Q.getKind() == NestedNameSpecifier::Kind::Type)
+ if (CheckTemplate(Q.getAsType()->getAs<TemplateSpecializationType>()))
+ return true; // Case: enable_if< >::type.
return false;
}
AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument,
diff --git a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp
index 75f1107..07cd90d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp
@@ -32,13 +32,10 @@ AST_MATCHER_P(TemplateTypeParmDecl, hasUnnamedDefaultArgument,
void IncorrectEnableIfCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
templateTypeParmDecl(
- hasUnnamedDefaultArgument(
- elaboratedTypeLoc(
- hasNamedTypeLoc(templateSpecializationTypeLoc(
- loc(qualType(hasDeclaration(namedDecl(
- hasName("::std::enable_if"))))))
- .bind("enable_if_specialization")))
- .bind("elaborated")))
+ hasUnnamedDefaultArgument(templateSpecializationTypeLoc(
+ loc(qualType(hasDeclaration(namedDecl(
+ hasName("::std::enable_if"))))))
+ .bind("enable_if_specialization")))
.bind("enable_if"),
this);
}
@@ -46,13 +43,11 @@ void IncorrectEnableIfCheck::registerMatchers(MatchFinder *Finder) {
void IncorrectEnableIfCheck::check(const MatchFinder::MatchResult &Result) {
const auto *EnableIf =
Result.Nodes.getNodeAs<TemplateTypeParmDecl>("enable_if");
- const auto *ElaboratedLoc =
- Result.Nodes.getNodeAs<ElaboratedTypeLoc>("elaborated");
const auto *EnableIfSpecializationLoc =
Result.Nodes.getNodeAs<TemplateSpecializationTypeLoc>(
"enable_if_specialization");
- if (!EnableIf || !ElaboratedLoc || !EnableIfSpecializationLoc)
+ if (!EnableIf || !EnableIfSpecializationLoc)
return;
const SourceManager &SM = *Result.SourceManager;
@@ -62,8 +57,10 @@ void IncorrectEnableIfCheck::check(const MatchFinder::MatchResult &Result) {
auto Diag = diag(EnableIf->getBeginLoc(),
"incorrect std::enable_if usage detected; use "
"'typename std::enable_if<...>::type'");
+ // FIXME: This should handle the enable_if specialization already having an
+ // elaborated keyword.
if (!getLangOpts().CPlusPlus20) {
- Diag << FixItHint::CreateInsertion(ElaboratedLoc->getBeginLoc(),
+ Diag << FixItHint::CreateInsertion(EnableIfSpecializationLoc->getBeginLoc(),
"typename ");
}
Diag << FixItHint::CreateInsertion(RAngleLoc.getLocWithOffset(1), "::type");
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index 4b495e3..cda9c4e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -188,7 +188,7 @@ static bool isKnownToHaveValue(const Expr &Cond, const ASTContext &Ctx,
/// \return true iff all `CallExprs` visited have callees; false otherwise
/// indicating there is an unresolved indirect call.
static bool populateCallees(const Stmt *StmtNode,
- llvm::SmallSet<const Decl *, 16> &Callees) {
+ llvm::SmallPtrSet<const Decl *, 16> &Callees) {
if (const auto *Call = dyn_cast<CallExpr>(StmtNode)) {
const Decl *Callee = Call->getDirectCallee();
@@ -212,7 +212,7 @@ static bool populateCallees(const Stmt *StmtNode,
/// returns true iff `SCC` contains `Func` and its' function set overlaps with
/// `Callees`
static bool overlap(ArrayRef<CallGraphNode *> SCC,
- const llvm::SmallSet<const Decl *, 16> &Callees,
+ const llvm::SmallPtrSet<const Decl *, 16> &Callees,
const Decl *Func) {
bool ContainsFunc = false, Overlap = false;
@@ -264,7 +264,7 @@ static bool hasRecursionOverStaticLoopCondVariables(const Expr *Cond,
if (!hasStaticLocalVariable(Cond))
return false;
- llvm::SmallSet<const Decl *, 16> CalleesInLoop;
+ llvm::SmallPtrSet<const Decl *, 16> CalleesInLoop;
if (!populateCallees(LoopStmt, CalleesInLoop)) {
// If there are unresolved indirect calls, we assume there could
diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp
index f903e63..7d92ef3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp
@@ -67,15 +67,15 @@ public:
return Visit(T->getElementType().getTypePtr());
}
bool VisitEnumType(const EnumType *T) {
- if (isCompleteAndHasNoZeroValue(T->getDecl())) {
+ if (isCompleteAndHasNoZeroValue(T->getOriginalDecl())) {
FoundEnum = T;
return true;
}
return false;
}
bool VisitRecordType(const RecordType *T) {
- const RecordDecl *RD = T->getDecl();
- if (RD->isUnion())
+ const RecordDecl *RD = T->getOriginalDecl()->getDefinition();
+ if (!RD || RD->isUnion())
return false;
auto VisitField = [this](const FieldDecl *F) {
return Visit(F->getType().getTypePtr());
@@ -125,7 +125,7 @@ void InvalidEnumDefaultInitializationCheck::check(
if (!Finder.Visit(InitList->getArrayFiller()->getType().getTypePtr()))
return;
InitExpr = InitList;
- Enum = Finder.FoundEnum->getDecl();
+ Enum = Finder.FoundEnum->getOriginalDecl();
}
if (!InitExpr || !Enum)
diff --git a/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h b/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h
index dab64f74..04ba359 100644
--- a/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h
@@ -32,6 +32,9 @@ public:
using SourceRangeSet = std::set<SourceRange, SourceRangeLessThan>;
LambdaFunctionNameCheck(StringRef Name, ClangTidyContext *Context);
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus11;
+ }
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp
index bfa2ab5..5dc988d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp
@@ -39,24 +39,31 @@ static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee,
// std::move(). This will hopefully prevent erroneous replacements if the
// code does unusual things (e.g. create an alias for std::move() in
// another namespace).
- NestedNameSpecifier *NNS = Callee->getQualifier();
- if (!NNS) {
+ NestedNameSpecifier NNS = Callee->getQualifier();
+ switch (NNS.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
// Called as "move" (i.e. presumably the code had a "using std::move;").
// We still conservatively put a "std::" in front of the forward because
// we don't know whether the code also had a "using std::forward;".
Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName);
- } else if (const NamespaceBaseDecl *Namespace = NNS->getAsNamespace()) {
+ break;
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix();
if (Namespace->getName() == "std") {
- if (!NNS->getPrefix()) {
+ if (!Prefix) {
// Called as "std::move".
Diag << FixItHint::CreateReplacement(CallRange,
"std::" + ForwardName);
- } else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) {
+ } else if (Prefix.getKind() == NestedNameSpecifier::Kind::Global) {
// Called as "::std::move".
Diag << FixItHint::CreateReplacement(CallRange,
"::std::" + ForwardName);
}
}
+ break;
+ }
+ default:
+ return;
}
}
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/MultiLevelImplicitPointerConversionCheck.h b/clang-tools-extra/clang-tidy/bugprone/MultiLevelImplicitPointerConversionCheck.h
index ef5f9f1..5ec78be 100644
--- a/clang-tools-extra/clang-tidy/bugprone/MultiLevelImplicitPointerConversionCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/MultiLevelImplicitPointerConversionCheck.h
@@ -31,7 +31,7 @@ public:
}
private:
- bool const EnableInC;
+ const bool EnableInC;
};
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp
index b68888c..6344b4b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp
@@ -15,14 +15,12 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
-namespace {
-
// Determine if the result of an expression is "stored" in some way.
// It is true if the value is stored into a variable or used as initialization
// or passed to a function or constructor.
// For this use case compound assignments are not counted as a "store" (the 'E'
// expression should have pointer type).
-bool isExprValueStored(const Expr *E, ASTContext &C) {
+static bool isExprValueStored(const Expr *E, ASTContext &C) {
E = E->IgnoreParenCasts();
// Get first non-paren, non-cast parent.
ParentMapContext &PMap = C.getParentMapContext();
@@ -49,6 +47,8 @@ bool isExprValueStored(const Expr *E, ASTContext &C) {
return isa<CallExpr, CXXConstructExpr>(ParentE);
}
+namespace {
+
AST_MATCHER_P(CXXTryStmt, hasHandlerFor,
ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) {
diff --git a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.h b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.h
index b044219..888d29f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.h
@@ -23,6 +23,9 @@ namespace clang::tidy::bugprone {
class OptionalValueConversionCheck : public ClangTidyCheck {
public:
OptionalValueConversionCheck(StringRef Name, ClangTidyContext *Context);
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
diff --git a/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h b/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h
index f552965..293069f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h
@@ -21,6 +21,9 @@ class ParentVirtualCallCheck : public ClangTidyCheck {
public:
ParentVirtualCallCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h b/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h
index 7227c3d..f50ce99 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h
@@ -22,6 +22,9 @@ class SizeofContainerCheck : public ClangTidyCheck {
public:
SizeofContainerCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
index 88e048e6..8da6227 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
@@ -425,7 +425,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
"suspicious usage of 'sizeof(array)/sizeof(...)';"
" denominator differs from the size of array elements")
<< E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (NumTy && DenomTy && NumTy == DenomTy &&
+ } else if (NumTy && DenomTy && Ctx.hasSameType(NumTy, DenomTy) &&
!NumTy->isDependentType()) {
// Dependent type should not be compared.
diag(E->getOperatorLoc(),
@@ -434,7 +434,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
<< E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
} else if (!WarnOnSizeOfPointer) {
// When 'WarnOnSizeOfPointer' is enabled, these messages become redundant:
- if (PointedTy && DenomTy && PointedTy == DenomTy) {
+ if (PointedTy && DenomTy && Ctx.hasSameType(PointedTy, DenomTy)) {
diag(E->getOperatorLoc(),
"suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer "
"is divided by size of pointed type")
@@ -463,7 +463,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
const auto *SizeOfExpr =
Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-mul-expr");
- if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
+ if (Ctx.hasSameType(LPtrTy, RPtrTy) &&
+ Ctx.hasSameType(LPtrTy, SizeofArgTy)) {
diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "
"pointer arithmetic")
<< SizeOfExpr->getSourceRange() << E->getOperatorLoc()
@@ -477,7 +478,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
const auto *SizeOfExpr =
Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-div-expr");
- if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
+ if (Ctx.hasSameType(LPtrTy, RPtrTy) &&
+ Ctx.hasSameType(LPtrTy, SizeofArgTy)) {
diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "
"pointer arithmetic")
<< SizeOfExpr->getSourceRange() << E->getOperatorLoc()
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h
index e9f1a6a..7fcc4b6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h
@@ -40,7 +40,7 @@ protected:
static const char PointerTypeN[];
private:
- StringRef const SmartPointerName;
+ const StringRef SmartPointerName;
};
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp
index 81c38d0..5b1b28d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp
@@ -14,10 +14,8 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
-namespace {
-
-bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
- const StringLiteral *Lit) {
+static bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
+ const StringLiteral *Lit) {
// String literals surrounded by parentheses are assumed to be on purpose.
// i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
@@ -58,6 +56,8 @@ bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
return false;
}
+namespace {
+
AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
MaxConcatenatedTokens) {
return Node.getNumConcatenated() > 1 &&
diff --git a/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp
index ddbb14e..02f4421 100644
--- a/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp
@@ -169,15 +169,8 @@ void TaggedUnionMemberCountCheck::check(
if (!Root || !UnionField || !TagField)
return;
- const auto *UnionDef =
- UnionField->getType().getCanonicalType().getTypePtr()->getAsRecordDecl();
- const auto *EnumDef = llvm::dyn_cast<EnumDecl>(
- TagField->getType().getCanonicalType().getTypePtr()->getAsTagDecl());
-
- assert(UnionDef && "UnionDef is missing!");
- assert(EnumDef && "EnumDef is missing!");
- if (!UnionDef || !EnumDef)
- return;
+ const auto *UnionDef = UnionField->getType()->castAsRecordDecl();
+ const auto *EnumDef = TagField->getType()->castAsEnumDecl();
const std::size_t UnionMemberCount = llvm::range_size(UnionDef->fields());
auto [TagCount, CountingEnumConstantDecl] = getNumberOfEnumValues(EnumDef);
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp
index ac49415..3b6969a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp
@@ -33,7 +33,7 @@ AST_MATCHER(VarDecl, isReferenced) { return Node.isReferenced(); }
AST_MATCHER(VarDecl, explicitMarkUnused) {
// Implementations should not emit a warning that a name-independent
// declaration is used or unused.
- LangOptions const &LangOpts = Finder->getASTContext().getLangOpts();
+ const LangOptions &LangOpts = Finder->getASTContext().getLangOpts();
return Node.hasAttr<UnusedAttr>() ||
(LangOpts.CPlusPlus26 && Node.isPlaceholderVar(LangOpts));
}
diff --git a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp
index 2a0d0ad..2c2248a 100644
--- a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp
@@ -31,7 +31,7 @@ void DefaultOperatorNewAlignmentCheck::check(
return;
const TagDecl *D = T->getAsTagDecl();
// Alignment can not be obtained for undefined type.
- if (!D || !D->getDefinition() || !D->isCompleteDefinition())
+ if (!D || !D->isCompleteDefinition())
return;
ASTContext &Context = D->getASTContext();
diff --git a/clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp b/clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp
index 3b59d23..95536bb 100644
--- a/clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp
@@ -46,7 +46,9 @@ enum class ConversionKind {
ToLongDouble
};
-ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
+} // namespace
+
+static ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
return llvm::StringSwitch<ConversionKind>(FD->getName())
.Cases("atoi", "atol", ConversionKind::ToInt)
.Case("atoll", ConversionKind::ToLongInt)
@@ -54,8 +56,8 @@ ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
.Default(ConversionKind::None);
}
-ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
- const TargetInfo &TI) {
+static ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
+ const TargetInfo &TI) {
// Scan the format string for the first problematic format specifier, then
// report that as the conversion type. This will miss additional conversion
// specifiers, but that is acceptable behavior.
@@ -128,7 +130,7 @@ ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
return H.get();
}
-StringRef classifyConversionType(ConversionKind K) {
+static StringRef classifyConversionType(ConversionKind K) {
switch (K) {
case ConversionKind::None:
llvm_unreachable("Unexpected conversion kind");
@@ -148,7 +150,7 @@ StringRef classifyConversionType(ConversionKind K) {
llvm_unreachable("Unknown conversion kind");
}
-StringRef classifyReplacement(ConversionKind K) {
+static StringRef classifyReplacement(ConversionKind K) {
switch (K) {
case ConversionKind::None:
llvm_unreachable("Unexpected conversion kind");
@@ -173,7 +175,6 @@ StringRef classifyReplacement(ConversionKind K) {
}
llvm_unreachable("Unknown conversion kind");
}
-} // unnamed namespace
void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp
index f615976..dd913c9 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp
@@ -14,73 +14,73 @@ using namespace clang::ast_matchers;
namespace clang::tidy::cppcoreguidelines {
-static bool isCopyConstructible(CXXRecordDecl const &Node) {
+static bool isCopyConstructible(const CXXRecordDecl &Node) {
if (Node.needsOverloadResolutionForCopyConstructor() &&
Node.needsImplicitCopyConstructor()) {
// unresolved
- for (CXXBaseSpecifier const &BS : Node.bases()) {
- CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl();
+ for (const CXXBaseSpecifier &BS : Node.bases()) {
+ const CXXRecordDecl *BRD = BS.getType()->getAsCXXRecordDecl();
if (BRD != nullptr && !isCopyConstructible(*BRD))
return false;
}
}
if (Node.hasSimpleCopyConstructor())
return true;
- for (CXXConstructorDecl const *Ctor : Node.ctors())
+ for (const CXXConstructorDecl *Ctor : Node.ctors())
if (Ctor->isCopyConstructor())
return !Ctor->isDeleted();
return false;
}
-static bool isMoveConstructible(CXXRecordDecl const &Node) {
+static bool isMoveConstructible(const CXXRecordDecl &Node) {
if (Node.needsOverloadResolutionForMoveConstructor() &&
Node.needsImplicitMoveConstructor()) {
// unresolved
- for (CXXBaseSpecifier const &BS : Node.bases()) {
- CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl();
+ for (const CXXBaseSpecifier &BS : Node.bases()) {
+ const CXXRecordDecl *BRD = BS.getType()->getAsCXXRecordDecl();
if (BRD != nullptr && !isMoveConstructible(*BRD))
return false;
}
}
if (Node.hasSimpleMoveConstructor())
return true;
- for (CXXConstructorDecl const *Ctor : Node.ctors())
+ for (const CXXConstructorDecl *Ctor : Node.ctors())
if (Ctor->isMoveConstructor())
return !Ctor->isDeleted();
return false;
}
-static bool isCopyAssignable(CXXRecordDecl const &Node) {
+static bool isCopyAssignable(const CXXRecordDecl &Node) {
if (Node.needsOverloadResolutionForCopyAssignment() &&
Node.needsImplicitCopyAssignment()) {
// unresolved
- for (CXXBaseSpecifier const &BS : Node.bases()) {
- CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl();
+ for (const CXXBaseSpecifier &BS : Node.bases()) {
+ const CXXRecordDecl *BRD = BS.getType()->getAsCXXRecordDecl();
if (BRD != nullptr && !isCopyAssignable(*BRD))
return false;
}
}
if (Node.hasSimpleCopyAssignment())
return true;
- for (CXXMethodDecl const *Method : Node.methods())
+ for (const CXXMethodDecl *Method : Node.methods())
if (Method->isCopyAssignmentOperator())
return !Method->isDeleted();
return false;
}
-static bool isMoveAssignable(CXXRecordDecl const &Node) {
+static bool isMoveAssignable(const CXXRecordDecl &Node) {
if (Node.needsOverloadResolutionForMoveAssignment() &&
Node.needsImplicitMoveAssignment()) {
// unresolved
- for (CXXBaseSpecifier const &BS : Node.bases()) {
- CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl();
+ for (const CXXBaseSpecifier &BS : Node.bases()) {
+ const CXXRecordDecl *BRD = BS.getType()->getAsCXXRecordDecl();
if (BRD != nullptr && !isMoveAssignable(*BRD))
return false;
}
}
if (Node.hasSimpleMoveAssignment())
return true;
- for (CXXMethodDecl const *Method : Node.methods())
+ for (const CXXMethodDecl *Method : Node.methods())
if (Method->isMoveAssignmentOperator())
return !Method->isDeleted();
return false;
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
index 2fb4d7f..0abb000 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule STATIC
OwningMemoryCheck.cpp
PreferMemberInitializerCheck.cpp
ProBoundsArrayToPointerDecayCheck.cpp
+ ProBoundsAvoidUncheckedContainerAccess.cpp
ProBoundsConstantArrayIndexCheck.cpp
ProBoundsPointerArithmeticCheck.cpp
ProTypeConstCastCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
index 4b3b7bf..cc1ae15 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -36,6 +36,7 @@
#include "OwningMemoryCheck.h"
#include "PreferMemberInitializerCheck.h"
#include "ProBoundsArrayToPointerDecayCheck.h"
+#include "ProBoundsAvoidUncheckedContainerAccess.h"
#include "ProBoundsConstantArrayIndexCheck.h"
#include "ProBoundsPointerArithmeticCheck.h"
#include "ProTypeConstCastCheck.h"
@@ -107,6 +108,8 @@ public:
"cppcoreguidelines-prefer-member-initializer");
CheckFactories.registerCheck<ProBoundsArrayToPointerDecayCheck>(
"cppcoreguidelines-pro-bounds-array-to-pointer-decay");
+ CheckFactories.registerCheck<ProBoundsAvoidUncheckedContainerAccess>(
+ "cppcoreguidelines-pro-bounds-avoid-unchecked-container-access");
CheckFactories.registerCheck<ProBoundsConstantArrayIndexCheck>(
"cppcoreguidelines-pro-bounds-constant-array-index");
CheckFactories.registerCheck<ProBoundsPointerArithmeticCheck>(
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
index 82d1cf1..75da6de 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
@@ -45,7 +45,7 @@ AST_MATCHER(ParmVarDecl, isTemplateTypeParameter) {
QualType ParamType =
Node.getType().getNonPackExpansionType()->getPointeeType();
- const auto *TemplateType = ParamType->getAs<TemplateTypeParmType>();
+ const auto *TemplateType = ParamType->getAsCanonical<TemplateTypeParmType>();
if (!TemplateType)
return false;
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp
index ca29317..29470b1 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp
@@ -23,9 +23,9 @@ void NoSuspendWithLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
}
void NoSuspendWithLockCheck::registerMatchers(MatchFinder *Finder) {
- auto LockType = elaboratedType(namesType(templateSpecializationType(
+ auto LockType = templateSpecializationType(
hasDeclaration(namedDecl(matchers::matchesAnyListedName(
- utils::options::parseStringList(LockGuards)))))));
+ utils::options::parseStringList(LockGuards)))));
StatementMatcher Lock =
declStmt(has(varDecl(hasType(LockType)).bind("lock-decl")))
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
index 593a4f8..79cd4bb 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
@@ -191,6 +191,9 @@ void PreferMemberInitializerCheck::check(
if (!AssignmentToMember)
continue;
const FieldDecl *Field = AssignmentToMember->Field;
+ // Skip if the field is inherited from a base class.
+ if (Field->getParent() != Class)
+ continue;
const Expr *InitValue = AssignmentToMember->Init;
updateAssignmentLevel(Field, InitValue, Ctor, AssignedFields);
if (!canAdvanceAssignment(AssignedFields[Field]))
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.cpp
new file mode 100644
index 0000000..35f432e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.cpp
@@ -0,0 +1,262 @@
+//===--- ProBoundsAvoidUncheckedContainerAccess.cpp - clang-tidy ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProBoundsAvoidUncheckedContainerAccess.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr llvm::StringRef DefaultExclusionStr =
+ "::std::map;::std::unordered_map;::std::flat_map";
+
+ProBoundsAvoidUncheckedContainerAccess::ProBoundsAvoidUncheckedContainerAccess(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ ExcludedClasses(utils::options::parseStringList(
+ Options.get("ExcludeClasses", DefaultExclusionStr))),
+ FixMode(Options.get("FixMode", None)),
+ FixFunction(Options.get("FixFunction", "gsl::at")),
+ FixFunctionEmptyArgs(Options.get("FixFunctionEmptyArgs", FixFunction)) {}
+
+void ProBoundsAvoidUncheckedContainerAccess::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ExcludeClasses",
+ utils::options::serializeStringList(ExcludedClasses));
+ Options.store(Opts, "FixMode", FixMode);
+ Options.store(Opts, "FixFunction", FixFunction);
+ Options.store(Opts, "FixFunctionEmptyArgs", FixFunctionEmptyArgs);
+}
+
+// TODO: if at() is defined in another class in the class hierarchy of the class
+// that defines the operator[] we matched on, findAlternative() will not detect
+// it.
+static const CXXMethodDecl *
+findAlternativeAt(const CXXMethodDecl *MatchedOperator) {
+ const CXXRecordDecl *Parent = MatchedOperator->getParent();
+ const QualType SubscriptThisObjType =
+ MatchedOperator->getFunctionObjectParameterReferenceType();
+
+ for (const CXXMethodDecl *Method : Parent->methods()) {
+ // Require 'Method' to be as accessible as 'MatchedOperator' or more
+ if (MatchedOperator->getAccess() < Method->getAccess())
+ continue;
+
+ if (MatchedOperator->isConst() != Method->isConst())
+ continue;
+
+ const QualType AtThisObjType =
+ Method->getFunctionObjectParameterReferenceType();
+ if (SubscriptThisObjType != AtThisObjType)
+ continue;
+
+ if (!Method->getNameInfo().getName().isIdentifier() ||
+ Method->getName() != "at")
+ continue;
+
+ const bool SameReturnType =
+ Method->getReturnType() == MatchedOperator->getReturnType();
+ if (!SameReturnType)
+ continue;
+
+ const bool SameNumberOfArguments =
+ Method->getNumParams() == MatchedOperator->getNumParams();
+ if (!SameNumberOfArguments)
+ continue;
+
+ for (unsigned ArgInd = 0; ArgInd < Method->getNumParams(); ArgInd++) {
+ const bool SameArgType =
+ Method->parameters()[ArgInd]->getOriginalType() ==
+ MatchedOperator->parameters()[ArgInd]->getOriginalType();
+ if (!SameArgType)
+ continue;
+ }
+
+ return Method;
+ }
+ return nullptr;
+}
+
+void ProBoundsAvoidUncheckedContainerAccess::registerMatchers(
+ MatchFinder *Finder) {
+ Finder->addMatcher(
+ mapAnyOf(cxxOperatorCallExpr, cxxMemberCallExpr)
+ .with(callee(
+ cxxMethodDecl(
+ hasOverloadedOperatorName("[]"),
+ anyOf(parameterCountIs(0), parameterCountIs(1)),
+ unless(matchers::matchesAnyListedName(ExcludedClasses)))
+ .bind("operator")))
+ .bind("caller"),
+ this);
+}
+
+void ProBoundsAvoidUncheckedContainerAccess::check(
+ const MatchFinder::MatchResult &Result) {
+
+ const auto *MatchedExpr = Result.Nodes.getNodeAs<CallExpr>("caller");
+
+ if (FixMode == None) {
+ diag(MatchedExpr->getCallee()->getBeginLoc(),
+ "possibly unsafe 'operator[]', consider bounds-safe alternatives")
+ << MatchedExpr->getCallee()->getSourceRange();
+ return;
+ }
+
+ if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(MatchedExpr)) {
+ // Case: a[i]
+ const auto LeftBracket = SourceRange(OCE->getCallee()->getBeginLoc(),
+ OCE->getCallee()->getBeginLoc());
+ const auto RightBracket =
+ SourceRange(OCE->getOperatorLoc(), OCE->getOperatorLoc());
+
+ if (FixMode == At) {
+ // Case: a[i] => a.at(i)
+ const auto *MatchedOperator =
+ Result.Nodes.getNodeAs<CXXMethodDecl>("operator");
+ const CXXMethodDecl *Alternative = findAlternativeAt(MatchedOperator);
+
+ if (!Alternative) {
+ diag(MatchedExpr->getCallee()->getBeginLoc(),
+ "possibly unsafe 'operator[]', consider "
+ "bounds-safe alternatives")
+ << MatchedExpr->getCallee()->getSourceRange();
+ return;
+ }
+
+ diag(MatchedExpr->getCallee()->getBeginLoc(),
+ "possibly unsafe 'operator[]', consider "
+ "bounds-safe alternative 'at()'")
+ << MatchedExpr->getCallee()->getSourceRange()
+ << FixItHint::CreateReplacement(LeftBracket, ".at(")
+ << FixItHint::CreateReplacement(RightBracket, ")");
+
+ diag(Alternative->getBeginLoc(), "viable 'at()' is defined here",
+ DiagnosticIDs::Note)
+ << Alternative->getNameInfo().getSourceRange();
+
+ } else if (FixMode == Function) {
+ // Case: a[i] => f(a, i)
+ //
+ // Since C++23, the subscript operator may also be called without an
+ // argument, which makes the following distinction necessary
+ const bool EmptySubscript =
+ MatchedExpr->getDirectCallee()->getNumParams() == 0;
+
+ if (EmptySubscript) {
+ auto D = diag(MatchedExpr->getCallee()->getBeginLoc(),
+ "possibly unsafe 'operator[]'%select{, use safe "
+ "function '%1() instead|}0")
+ << FixFunctionEmptyArgs.empty() << FixFunctionEmptyArgs.str()
+ << MatchedExpr->getCallee()->getSourceRange();
+ if (!FixFunctionEmptyArgs.empty()) {
+ D << FixItHint::CreateInsertion(OCE->getArg(0)->getBeginLoc(),
+ FixFunctionEmptyArgs.str() + "(")
+ << FixItHint::CreateRemoval(LeftBracket)
+ << FixItHint::CreateReplacement(RightBracket, ")");
+ }
+ } else {
+ diag(MatchedExpr->getCallee()->getBeginLoc(),
+ "possibly unsafe 'operator[]', use safe function '%0()' instead")
+ << FixFunction.str() << MatchedExpr->getCallee()->getSourceRange()
+ << FixItHint::CreateInsertion(OCE->getArg(0)->getBeginLoc(),
+ FixFunction.str() + "(")
+ << FixItHint::CreateReplacement(LeftBracket, ", ")
+ << FixItHint::CreateReplacement(RightBracket, ")");
+ }
+ }
+ } else if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(MatchedExpr)) {
+ // Case: a.operator[](i) or a->operator[](i)
+ const auto *Callee = dyn_cast<MemberExpr>(MCE->getCallee());
+
+ if (FixMode == At) {
+ // Cases: a.operator[](i) => a.at(i) and a->operator[](i) => a->at(i)
+
+ const auto *MatchedOperator =
+ Result.Nodes.getNodeAs<CXXMethodDecl>("operator");
+
+ const CXXMethodDecl *Alternative = findAlternativeAt(MatchedOperator);
+ if (!Alternative) {
+ diag(Callee->getBeginLoc(), "possibly unsafe 'operator[]', consider "
+ "bounds-safe alternative 'at()'")
+ << Callee->getSourceRange();
+ return;
+ }
+ diag(MatchedExpr->getCallee()->getBeginLoc(),
+ "possibly unsafe 'operator[]', consider "
+ "bounds-safe alternative 'at()'")
+ << FixItHint::CreateReplacement(
+ SourceRange(Callee->getMemberLoc(), Callee->getEndLoc()),
+ "at");
+
+ diag(Alternative->getBeginLoc(), "viable 'at()' defined here",
+ DiagnosticIDs::Note)
+ << Alternative->getNameInfo().getSourceRange();
+
+ } else if (FixMode == Function) {
+ // Cases: a.operator[](i) => f(a, i) and a->operator[](i) => f(*a, i)
+ const auto *Callee = dyn_cast<MemberExpr>(MCE->getCallee());
+
+ const bool EmptySubscript =
+ MCE->getMethodDecl()->getNumNonObjectParams() == 0;
+
+ std::string BeginInsertion =
+ (EmptySubscript ? FixFunctionEmptyArgs.str() : FixFunction.str()) +
+ "(";
+
+ if (Callee->isArrow())
+ BeginInsertion += "*";
+
+ // Since C++23, the subscript operator may also be called without an
+ // argument, which makes the following distinction necessary
+ if (EmptySubscript) {
+ auto D = diag(MatchedExpr->getCallee()->getBeginLoc(),
+ "possibly unsafe 'operator[]'%select{, use safe "
+ "function '%1()' instead|}0")
+ << FixFunctionEmptyArgs.empty() << FixFunctionEmptyArgs.str()
+ << Callee->getSourceRange();
+
+ if (!FixFunctionEmptyArgs.empty()) {
+ D << FixItHint::CreateInsertion(MatchedExpr->getBeginLoc(),
+ BeginInsertion)
+ << FixItHint::CreateRemoval(
+ SourceRange(Callee->getOperatorLoc(),
+ MCE->getRParenLoc().getLocWithOffset(-1)));
+ }
+ } else {
+ diag(Callee->getBeginLoc(),
+ "possibly unsafe 'operator[]', use safe function '%0()' instead")
+ << FixFunction.str() << Callee->getSourceRange()
+ << FixItHint::CreateInsertion(MatchedExpr->getBeginLoc(),
+ BeginInsertion)
+ << FixItHint::CreateReplacement(
+ SourceRange(
+ Callee->getOperatorLoc(),
+ MCE->getArg(0)->getBeginLoc().getLocWithOffset(-1)),
+ ", ");
+ }
+ }
+ }
+}
+
+} // namespace clang::tidy::cppcoreguidelines
+
+namespace clang::tidy {
+using P = cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccess;
+
+llvm::ArrayRef<std::pair<P::FixModes, StringRef>>
+OptionEnumMapping<P::FixModes>::getEnumMapping() {
+ static constexpr std::pair<P::FixModes, StringRef> Mapping[] = {
+ {P::None, "none"}, {P::At, "at"}, {P::Function, "function"}};
+ return {Mapping};
+}
+} // namespace clang::tidy
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.h
new file mode 100644
index 0000000..cfd52d6
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsAvoidUncheckedContainerAccess.h
@@ -0,0 +1,56 @@
+//===--- ProBoundsAvoidUncheckedContainerAccess.h - clang-tidy --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_AVOID_UNCHECKED_CONTAINER_ACCESS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_AVOID_UNCHECKED_CONTAINER_ACCESS_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::cppcoreguidelines {
+
+/// Flags calls to operator[] in STL containers and suggests replacing it with
+/// safe alternatives.
+///
+/// See
+/// https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#slcon3-avoid-bounds-errors
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.html
+class ProBoundsAvoidUncheckedContainerAccess : public ClangTidyCheck {
+public:
+ ProBoundsAvoidUncheckedContainerAccess(StringRef Name,
+ ClangTidyContext *Context);
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+ enum FixModes { None, At, Function };
+
+private:
+ // A list of class names that are excluded from the warning
+ std::vector<llvm::StringRef> ExcludedClasses;
+ // Setting which fix to suggest
+ FixModes FixMode;
+ llvm::StringRef FixFunction;
+ llvm::StringRef FixFunctionEmptyArgs;
+};
+} // namespace clang::tidy::cppcoreguidelines
+
+namespace clang::tidy {
+template <>
+struct OptionEnumMapping<
+ cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccess::FixModes> {
+ static ArrayRef<std::pair<
+ cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccess::FixModes,
+ StringRef>>
+ getEnumMapping();
+};
+} // namespace clang::tidy
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_AVOID_UNCHECKED_CONTAINER_ACCESS_H
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
index 9ac7b9e..51995c5 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
@@ -14,6 +14,18 @@ using namespace clang::ast_matchers;
namespace clang::tidy::cppcoreguidelines {
+ProBoundsPointerArithmeticCheck::ProBoundsPointerArithmeticCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ AllowIncrementDecrementOperators(
+ Options.get("AllowIncrementDecrementOperators", false)) {}
+
+void ProBoundsPointerArithmeticCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "AllowIncrementDecrementOperators",
+ AllowIncrementDecrementOperators);
+}
+
void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) {
const auto AllPointerTypes =
anyOf(hasType(hasUnqualifiedDesugaredType(pointerType())),
@@ -30,13 +42,14 @@ void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) {
this);
// Flag all operators ++, -- that result in a pointer
- Finder->addMatcher(
- unaryOperator(hasAnyOperatorName("++", "--"),
- hasType(hasUnqualifiedDesugaredType(pointerType())),
- unless(hasUnaryOperand(
- ignoringImpCasts(declRefExpr(to(isImplicit()))))))
- .bind("expr"),
- this);
+ if (!AllowIncrementDecrementOperators)
+ Finder->addMatcher(
+ unaryOperator(hasAnyOperatorName("++", "--"),
+ hasType(hasUnqualifiedDesugaredType(pointerType())),
+ unless(hasUnaryOperand(
+ ignoringImpCasts(declRefExpr(to(isImplicit()))))))
+ .bind("expr"),
+ this);
// Array subscript on a pointer (not an array) is also pointer arithmetic
Finder->addMatcher(
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h
index 3466c72..785f754 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h
@@ -21,13 +21,16 @@ namespace clang::tidy::cppcoreguidelines {
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/pro-bounds-pointer-arithmetic.html
class ProBoundsPointerArithmeticCheck : public ClangTidyCheck {
public:
- ProBoundsPointerArithmeticCheck(StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context) {}
+ ProBoundsPointerArithmeticCheck(StringRef Name, ClangTidyContext *Context);
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool AllowIncrementDecrementOperators;
};
} // namespace clang::tidy::cppcoreguidelines
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
index b413b12..e6e79f0 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -189,8 +189,8 @@ struct InitializerInsertion {
// Convenience utility to get a RecordDecl from a QualType.
const RecordDecl *getCanonicalRecordDecl(const QualType &Type) {
- if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>())
- return RT->getDecl();
+ if (const auto *RT = Type->getAsCanonical<RecordType>())
+ return RT->getOriginalDecl();
return nullptr;
}
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp
index 7675439..6508bfd5 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp
@@ -90,9 +90,8 @@ void SlicingCheck::diagnoseSlicedOverriddenMethods(
}
// Recursively process bases.
for (const auto &Base : DerivedDecl.bases()) {
- if (const auto *BaseRecordType = Base.getType()->getAs<RecordType>()) {
- if (const auto *BaseRecord = cast_or_null<CXXRecordDecl>(
- BaseRecordType->getDecl()->getDefinition()))
+ if (const auto *BaseRecord = Base.getType()->getAsCXXRecordDecl()) {
+ if (BaseRecord->isCompleteDefinition())
diagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl);
}
}
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h
index 02bfaf1..317547f 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h
@@ -22,6 +22,9 @@ class SlicingCheck : public ClangTidyCheck {
public:
SlicingCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
diff --git a/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCallsCheck.h b/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCallsCheck.h
index 49d7820..120dc90 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCallsCheck.h
+++ b/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCallsCheck.h
@@ -21,6 +21,9 @@ class DefaultArgumentsCallsCheck : public ClangTidyCheck {
public:
DefaultArgumentsCallsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsDeclarationsCheck.h b/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsDeclarationsCheck.h
index d03d0b7..da73fa4 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsDeclarationsCheck.h
+++ b/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsDeclarationsCheck.h
@@ -21,6 +21,9 @@ class DefaultArgumentsDeclarationsCheck : public ClangTidyCheck {
public:
DefaultArgumentsDeclarationsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
index 80ff97a..4382f9d 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
@@ -39,7 +39,7 @@ bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node,
bool &IsInterface) const {
assert(Node->getIdentifier());
StringRef Name = Node->getIdentifier()->getName();
- llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(Name);
+ auto Pair = InterfaceMap.find(Name);
if (Pair == InterfaceMap.end())
return false;
IsInterface = Pair->second;
@@ -71,13 +71,10 @@ bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) {
for (const auto &I : Node->bases()) {
if (I.isVirtual())
continue;
- const auto *Ty = I.getType()->getAs<RecordType>();
- if (!Ty)
+ const auto *Base = I.getType()->getAsCXXRecordDecl();
+ if (!Base)
continue;
- const RecordDecl *D = Ty->getDecl()->getDefinition();
- if (!D)
- continue;
- const auto *Base = cast<CXXRecordDecl>(D);
+ assert(Base->isCompleteDefinition());
if (!isInterface(Base)) {
addNodeToInterfaceMap(Node, false);
return false;
@@ -103,10 +100,10 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
for (const auto &I : D->bases()) {
if (I.isVirtual())
continue;
- const auto *Ty = I.getType()->getAs<RecordType>();
- if (!Ty)
+ const auto *Base = I.getType()->getAsCXXRecordDecl();
+ if (!Base)
continue;
- const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
+ assert(Base->isCompleteDefinition());
if (!isInterface(Base))
NumConcrete++;
}
@@ -114,10 +111,10 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
// Check virtual bases to see if there is more than one concrete
// non-virtual base.
for (const auto &V : D->vbases()) {
- const auto *Ty = V.getType()->getAs<RecordType>();
- if (!Ty)
+ const auto *Base = V.getType()->getAsCXXRecordDecl();
+ if (!Base)
continue;
- const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
+ assert(Base->isCompleteDefinition());
if (!isInterface(Base))
NumConcrete++;
}
diff --git a/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h b/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h
index 007f410..d26349d 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h
+++ b/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h
@@ -21,6 +21,9 @@ class OverloadedOperatorCheck : public ClangTidyCheck {
public:
OverloadedOperatorCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h b/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h
index 426d89d..1bdf19f 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h
+++ b/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h
@@ -21,6 +21,9 @@ class VirtualInheritanceCheck : public ClangTidyCheck {
public:
VirtualInheritanceCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
index e076b39..14e11eb 100644
--- a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
@@ -89,6 +89,30 @@ static StringRef getDestTypeString(const SourceManager &SM,
SM, LangOpts);
}
+static bool sameTypeAsWritten(QualType X, QualType Y) {
+ if (X.getCanonicalType() != Y.getCanonicalType())
+ return false;
+
+ auto TC = X->getTypeClass();
+ if (TC != Y->getTypeClass())
+ return false;
+
+ switch (TC) {
+ case Type::Typedef:
+ return declaresSameEntity(cast<TypedefType>(X)->getDecl(),
+ cast<TypedefType>(Y)->getDecl());
+ case Type::Pointer:
+ return sameTypeAsWritten(cast<PointerType>(X)->getPointeeType(),
+ cast<PointerType>(Y)->getPointeeType());
+ case Type::RValueReference:
+ case Type::LValueReference:
+ return sameTypeAsWritten(cast<ReferenceType>(X)->getPointeeType(),
+ cast<ReferenceType>(Y)->getPointeeType());
+ default:
+ return true;
+ }
+}
+
void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
@@ -128,12 +152,7 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
// case of overloaded functions, so detection of redundant casts is trickier
// in this case. Don't emit "redundant cast" warnings for function
// pointer/reference types.
- QualType Src = SourceTypeAsWritten, Dst = DestTypeAsWritten;
- if (const auto *ElTy = dyn_cast<ElaboratedType>(Src))
- Src = ElTy->getNamedType();
- if (const auto *ElTy = dyn_cast<ElaboratedType>(Dst))
- Dst = ElTy->getNamedType();
- if (Src == Dst) {
+ if (sameTypeAsWritten(SourceTypeAsWritten, DestTypeAsWritten)) {
diag(CastExpr->getBeginLoc(), "redundant cast to the same type")
<< FixItHint::CreateRemoval(ReplaceRange);
return;
diff --git a/clang-tools-extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h b/clang-tools-extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h
index baec40e..b53e6c4 100644
--- a/clang-tools-extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h
+++ b/clang-tools-extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h
@@ -21,6 +21,9 @@ namespace clang::tidy::google::readability {
class AvoidUnderscoreInGoogletestNameCheck : public ClangTidyCheck {
public:
using ClangTidyCheck::ClangTidyCheck;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
Preprocessor *ModuleExpanderPP) override;
diff --git a/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h b/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h
index a8f0b01..49d95a5 100644
--- a/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h
+++ b/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h
@@ -23,6 +23,9 @@ class DefaultArgumentsCheck : public ClangTidyCheck {
public:
DefaultArgumentsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp b/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp
index 3deea06..68233ec 100644
--- a/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp
@@ -72,7 +72,7 @@ static bool isStdInitializerList(QualType Type) {
}
if (const auto *RT = Type->getAs<RecordType>()) {
if (const auto *Specialization =
- dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()))
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl()))
return declIsStdInitializerList(Specialization->getSpecializedTemplate());
}
return false;
diff --git a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
index 805dcaf..274b8af 100644
--- a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
@@ -257,8 +257,13 @@ getAliasNameRange(const MatchFinder::MatchResult &Result) {
return CharSourceRange::getTokenRange(
Using->getNameInfo().getSourceRange());
}
- return CharSourceRange::getTokenRange(
- Result.Nodes.getNodeAs<TypeLoc>("typeloc")->getSourceRange());
+ TypeLoc TL = *Result.Nodes.getNodeAs<TypeLoc>("typeloc");
+ if (auto QTL = TL.getAs<QualifiedTypeLoc>())
+ TL = QTL.getUnqualifiedLoc();
+
+ if (auto TTL = TL.getAs<TypedefTypeLoc>())
+ return CharSourceRange::getTokenRange(TTL.getNameLoc());
+ return CharSourceRange::getTokenRange(TL.castAs<UsingTypeLoc>().getNameLoc());
}
void UpgradeGoogletestCaseCheck::check(const MatchFinder::MatchResult &Result) {
diff --git a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.h b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.h
index 48354c3..39c45fe 100644
--- a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.h
+++ b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.h
@@ -21,6 +21,9 @@ namespace clang::tidy::hicpp {
class IgnoredRemoveResultCheck : public bugprone::UnusedReturnValueCheck {
public:
IgnoredRemoveResultCheck(StringRef Name, ClangTidyContext *Context);
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
};
diff --git a/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.h b/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.h
index 1099ab0..07e018a 100644
--- a/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.h
@@ -23,6 +23,9 @@ class PreferRegisterOverUnsignedCheck : public ClangTidyCheck {
public:
PreferRegisterOverUnsignedCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h b/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h
index e1f25e5..b4550ec 100644
--- a/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h
@@ -19,6 +19,9 @@ class TwineLocalCheck : public ClangTidyCheck {
public:
TwineLocalCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index fd7affd..2cfee5f 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -32,6 +32,7 @@ add_clang_library(clangTidyMiscModule STATIC
NoRecursionCheck.cpp
NonCopyableObjects.cpp
NonPrivateMemberVariablesInClassesCheck.cpp
+ OverrideWithDifferentVisibilityCheck.cpp
RedundantExpressionCheck.cpp
StaticAssertCheck.cpp
ThrowByValueCatchByReferenceCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
index 697398a..b32507d 100644
--- a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
@@ -98,11 +98,12 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))),
hasType(referenceType(pointee(substTemplateTypeParmType()))));
- const auto AllowedType = hasType(qualType(anyOf(
- hasDeclaration(namedDecl(matchers::matchesAnyListedName(AllowedTypes))),
- references(namedDecl(matchers::matchesAnyListedName(AllowedTypes))),
- pointerType(pointee(hasDeclaration(
- namedDecl(matchers::matchesAnyListedName(AllowedTypes))))))));
+ auto AllowedTypeDecl = namedDecl(
+ anyOf(matchers::matchesAnyListedName(AllowedTypes), usingShadowDecl()));
+
+ const auto AllowedType = hasType(qualType(
+ anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl),
+ pointerType(pointee(hasDeclaration(AllowedTypeDecl))))));
const auto AutoTemplateType = varDecl(
anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))),
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index 6ddebcb..f675ca7 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -22,6 +22,7 @@
#include "NoRecursionCheck.h"
#include "NonCopyableObjects.h"
#include "NonPrivateMemberVariablesInClassesCheck.h"
+#include "OverrideWithDifferentVisibilityCheck.h"
#include "RedundantExpressionCheck.h"
#include "StaticAssertCheck.h"
#include "ThrowByValueCatchByReferenceCheck.h"
@@ -81,6 +82,8 @@ public:
"misc-use-anonymous-namespace");
CheckFactories.registerCheck<UseInternalLinkageCheck>(
"misc-use-internal-linkage");
+ CheckFactories.registerCheck<OverrideWithDifferentVisibilityCheck>(
+ "misc-override-with-different-visibility");
}
};
diff --git a/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp b/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp
index 0cdd48c..bb64a56 100644
--- a/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp
@@ -19,13 +19,13 @@ void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
pointee(anyOf(isConstQualified(), ignoringParens(functionType()))))));
Finder->addMatcher(
- valueDecl(hasType(qualType(
- isConstQualified(),
- elaboratedType(namesType(typedefType(hasDeclaration(
- anyOf(typedefDecl(NonConstAndNonFunctionPointerType)
- .bind("typedef"),
- typeAliasDecl(NonConstAndNonFunctionPointerType)
- .bind("typeAlias")))))))))
+ valueDecl(
+ hasType(qualType(isConstQualified(),
+ typedefType(hasDeclaration(anyOf(
+ typedefDecl(NonConstAndNonFunctionPointerType)
+ .bind("typedef"),
+ typeAliasDecl(NonConstAndNonFunctionPointerType)
+ .bind("typeAlias")))))))
.bind("decl"),
this);
}
diff --git a/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp b/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp
index 40808aa..2837f40 100644
--- a/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp
@@ -59,7 +59,9 @@ AST_MATCHER(FunctionDecl, isPlacementOverload) {
return true;
}
-OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
+} // namespace
+
+static OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
switch (FD->getOverloadedOperator()) {
default:
break;
@@ -75,7 +77,7 @@ OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
llvm_unreachable("Not an overloaded allocation operator");
}
-const char *getOperatorName(OverloadedOperatorKind K) {
+static const char *getOperatorName(OverloadedOperatorKind K) {
switch (K) {
default:
break;
@@ -91,13 +93,14 @@ const char *getOperatorName(OverloadedOperatorKind K) {
llvm_unreachable("Not an overloaded allocation operator");
}
-bool areCorrespondingOverloads(const FunctionDecl *LHS,
- const FunctionDecl *RHS) {
+static bool areCorrespondingOverloads(const FunctionDecl *LHS,
+ const FunctionDecl *RHS) {
return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
}
-bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
- const CXXRecordDecl *RD = nullptr) {
+static bool
+hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
+ const CXXRecordDecl *RD = nullptr) {
if (RD) {
// Check the methods in the given class and accessible to derived classes.
for (const auto *BMD : RD->methods())
@@ -124,8 +127,6 @@ bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
return false;
}
-} // anonymous namespace
-
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
// Match all operator new and operator delete overloads (including the array
// forms). Do not match implicit operators, placement operators, or
diff --git a/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp
new file mode 100644
index 0000000..2fe0bcf
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp
@@ -0,0 +1,150 @@
+//===--- OverrideWithDifferentVisibilityCheck.cpp - clang-tidy ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "OverrideWithDifferentVisibilityCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang;
+
+namespace {
+
+AST_MATCHER(NamedDecl, isOperatorDecl) {
+ const DeclarationName::NameKind NK = Node.getDeclName().getNameKind();
+ return NK != DeclarationName::Identifier &&
+ NK != DeclarationName::CXXConstructorName &&
+ NK != DeclarationName::CXXDestructorName;
+}
+
+} // namespace
+
+namespace clang::tidy {
+
+template <>
+struct OptionEnumMapping<
+ misc::OverrideWithDifferentVisibilityCheck::ChangeKind> {
+ static llvm::ArrayRef<std::pair<
+ misc::OverrideWithDifferentVisibilityCheck::ChangeKind, StringRef>>
+ getEnumMapping() {
+ static constexpr std::pair<
+ misc::OverrideWithDifferentVisibilityCheck::ChangeKind, StringRef>
+ Mapping[] = {
+ {misc::OverrideWithDifferentVisibilityCheck::ChangeKind::Any,
+ "any"},
+ {misc::OverrideWithDifferentVisibilityCheck::ChangeKind::Widening,
+ "widening"},
+ {misc::OverrideWithDifferentVisibilityCheck::ChangeKind::Narrowing,
+ "narrowing"},
+ };
+ return {Mapping};
+ }
+};
+
+namespace misc {
+
+OverrideWithDifferentVisibilityCheck::OverrideWithDifferentVisibilityCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ DetectVisibilityChange(
+ Options.get("DisallowedVisibilityChange", ChangeKind::Any)),
+ CheckDestructors(Options.get("CheckDestructors", false)),
+ CheckOperators(Options.get("CheckOperators", false)),
+ IgnoredFunctions(utils::options::parseStringList(
+ Options.get("IgnoredFunctions", ""))) {}
+
+void OverrideWithDifferentVisibilityCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "DisallowedVisibilityChange", DetectVisibilityChange);
+ Options.store(Opts, "CheckDestructors", CheckDestructors);
+ Options.store(Opts, "CheckOperators", CheckOperators);
+ Options.store(Opts, "IgnoredFunctions",
+ utils::options::serializeStringList(IgnoredFunctions));
+}
+
+void OverrideWithDifferentVisibilityCheck::registerMatchers(
+ MatchFinder *Finder) {
+ const auto IgnoredDecl =
+ namedDecl(matchers::matchesAnyListedName(IgnoredFunctions));
+ const auto FilterDestructors =
+ CheckDestructors ? decl() : decl(unless(cxxDestructorDecl()));
+ const auto FilterOperators =
+ CheckOperators ? namedDecl() : namedDecl(unless(isOperatorDecl()));
+ Finder->addMatcher(
+ cxxMethodDecl(
+ isVirtual(), FilterDestructors, FilterOperators,
+ ofClass(
+ cxxRecordDecl(unless(isExpansionInSystemHeader())).bind("class")),
+ forEachOverridden(cxxMethodDecl(ofClass(cxxRecordDecl().bind("base")),
+ unless(IgnoredDecl))
+ .bind("base_func")))
+ .bind("func"),
+ this);
+}
+
+void OverrideWithDifferentVisibilityCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *const MatchedFunction =
+ Result.Nodes.getNodeAs<FunctionDecl>("func");
+ if (!MatchedFunction->isCanonicalDecl())
+ return;
+
+ const auto *const ParentClass =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("class");
+ const auto *const BaseClass = Result.Nodes.getNodeAs<CXXRecordDecl>("base");
+ CXXBasePaths Paths;
+ if (!ParentClass->isDerivedFrom(BaseClass, Paths))
+ return;
+
+ const auto *const OverriddenFunction =
+ Result.Nodes.getNodeAs<FunctionDecl>("base_func");
+ const AccessSpecifier ActualAccess = MatchedFunction->getAccess();
+ AccessSpecifier OverriddenAccess = OverriddenFunction->getAccess();
+
+ const CXXBaseSpecifier *InheritanceWithStrictVisibility = nullptr;
+ for (const CXXBasePath &Path : Paths) {
+ for (const CXXBasePathElement &Elem : Path) {
+ if (Elem.Base->getAccessSpecifier() > OverriddenAccess) {
+ OverriddenAccess = Elem.Base->getAccessSpecifier();
+ InheritanceWithStrictVisibility = Elem.Base;
+ }
+ }
+ }
+
+ if (ActualAccess != OverriddenAccess) {
+ if (DetectVisibilityChange == ChangeKind::Widening &&
+ ActualAccess > OverriddenAccess)
+ return;
+ if (DetectVisibilityChange == ChangeKind::Narrowing &&
+ ActualAccess < OverriddenAccess)
+ return;
+
+ if (InheritanceWithStrictVisibility) {
+ diag(MatchedFunction->getLocation(),
+ "visibility of function %0 is changed from %1 (through %1 "
+ "inheritance of class %2) to %3")
+ << MatchedFunction << OverriddenAccess
+ << InheritanceWithStrictVisibility->getType() << ActualAccess;
+ diag(InheritanceWithStrictVisibility->getBeginLoc(),
+ "%0 is inherited as %1 here", DiagnosticIDs::Note)
+ << InheritanceWithStrictVisibility->getType() << OverriddenAccess;
+ } else {
+ diag(MatchedFunction->getLocation(),
+ "visibility of function %0 is changed from %1 in class %2 to %3")
+ << MatchedFunction << OverriddenAccess << BaseClass << ActualAccess;
+ }
+ diag(OverriddenFunction->getLocation(), "function declared here as %0",
+ DiagnosticIDs::Note)
+ << OverriddenFunction->getAccess();
+ }
+}
+
+} // namespace misc
+
+} // namespace clang::tidy
diff --git a/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h
new file mode 100644
index 0000000..1f5222d
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h
@@ -0,0 +1,43 @@
+//===--- OverrideWithDifferentVisibilityCheck.h - clang-tidy --*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OVERRIDEWITHDIFFERENTVISIBILITYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OVERRIDEWITHDIFFERENTVISIBILITYCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::misc {
+
+/// Finds virtual function overrides with different visibility than the function
+/// in the base class.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc/override-with-different-visibility.html
+class OverrideWithDifferentVisibilityCheck : public ClangTidyCheck {
+public:
+ enum class ChangeKind { Any, Widening, Narrowing };
+
+ OverrideWithDifferentVisibilityCheck(StringRef Name,
+ ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+
+private:
+ ChangeKind DetectVisibilityChange;
+ bool CheckDestructors;
+ bool CheckOperators;
+ std::vector<llvm::StringRef> IgnoredFunctions;
+};
+
+} // namespace clang::tidy::misc
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OVERRIDEWITHDIFFERENTVISIBILITYCHECK_H
diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
index 9b2af2a..107eda2 100644
--- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -45,14 +45,6 @@ static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) {
return Value < Result;
}
-static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left,
- const NestedNameSpecifier *Right) {
- llvm::FoldingSetNodeID LeftID, RightID;
- Left->Profile(LeftID);
- Right->Profile(RightID);
- return LeftID == RightID;
-}
-
static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
if (!Left || !Right)
return !Left && !Right;
@@ -104,9 +96,8 @@ static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
return false;
- return areEquivalentNameSpecifier(
- cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
- cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
+ return cast<DependentScopeDeclRefExpr>(Left)->getQualifier() ==
+ cast<DependentScopeDeclRefExpr>(Right)->getQualifier();
case Stmt::DeclRefExprClass:
return cast<DeclRefExpr>(Left)->getDecl() ==
cast<DeclRefExpr>(Right)->getDecl();
diff --git a/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
index 3fdaf92..8200239 100644
--- a/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
@@ -29,11 +29,13 @@ void UnconventionalAssignOperatorCheck::registerMatchers(
const auto HasGoodReturnType =
cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
unless(isConstQualified()),
- anyOf(autoType(), hasDeclaration(equalsBoundNode("class"))))))));
+ anyOf(autoType(),
+ hasDeclaration(declaresSameEntityAsBoundNode("class"))))))));
const auto IsSelf = qualType(hasCanonicalType(
- anyOf(hasDeclaration(equalsBoundNode("class")),
- referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))));
+ anyOf(hasDeclaration(declaresSameEntityAsBoundNode("class")),
+ referenceType(pointee(
+ hasDeclaration(declaresSameEntityAsBoundNode("class")))))));
const auto IsAssign =
cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
hasName("operator="), ofClass(recordDecl().bind("class")))
diff --git a/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp
index 86992cd..4fa679a 100644
--- a/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp
@@ -35,12 +35,12 @@ void UnusedAliasDeclsCheck::check(const MatchFinder::MatchResult &Result) {
}
if (const auto *NestedName =
- Result.Nodes.getNodeAs<NestedNameSpecifier>("nns")) {
- if (const auto *AliasDecl = dyn_cast_if_present<NamespaceAliasDecl>(
- NestedName->getAsNamespace())) {
+ Result.Nodes.getNodeAs<NestedNameSpecifier>("nns");
+ NestedName &&
+ NestedName->getKind() == NestedNameSpecifier::Kind::Namespace)
+ if (const auto *AliasDecl = dyn_cast<NamespaceAliasDecl>(
+ NestedName->getAsNamespaceAndPrefix().Namespace))
FoundDecls[AliasDecl] = CharSourceRange();
- }
- }
}
void UnusedAliasDeclsCheck::onEndOfTranslationUnit() {
diff --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
index d5c5fa3..4943207 100644
--- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
@@ -71,11 +71,7 @@ void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) {
templateArgument().bind("used")))),
this);
Finder->addMatcher(userDefinedLiteral().bind("used"), this);
- Finder->addMatcher(
- loc(elaboratedType(unless(hasQualifier(nestedNameSpecifier())),
- hasUnqualifiedDesugaredType(
- type(asTagDecl(tagDecl().bind("used")))))),
- this);
+ Finder->addMatcher(loc(asTagDecl(tagDecl().bind("used"))), this);
// Cases where we can identify the UsingShadowDecl directly, rather than
// just its target.
// FIXME: cover more cases in this way, as the AST supports it.
@@ -135,8 +131,8 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) {
return;
}
if (const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
- if (const auto *ET = ECD->getType()->getAs<EnumType>())
- removeFromFoundDecls(ET->getDecl());
+ if (const auto *ET = ECD->getType()->getAsCanonical<EnumType>())
+ removeFromFoundDecls(ET->getOriginalDecl());
}
};
// We rely on the fact that the clang AST is walked in order, usages are only
diff --git a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp
index f6404db..5d11843 100644
--- a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp
@@ -152,14 +152,14 @@ void ConcatNestedNamespacesCheck::reportDiagnostic(
ConcatNameSpace.append("::");
}
- for (SourceRange const &Front : Fronts)
+ for (const SourceRange &Front : Fronts)
DB << FixItHint::CreateRemoval(Front);
DB << FixItHint::CreateReplacement(
Namespaces.back().getReplacedNamespaceFrontRange(), ConcatNameSpace);
if (LastRBrace != Namespaces.back().getDefaultNamespaceBackRange())
DB << FixItHint::CreateReplacement(LastRBrace,
("} // " + ConcatNameSpace).str());
- for (SourceRange const &Back : llvm::reverse(Backs))
+ for (const SourceRange &Back : llvm::reverse(Backs))
DB << FixItHint::CreateRemoval(Back);
}
diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
index f22f48d..2aca610 100644
--- a/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
@@ -29,8 +29,7 @@ static std::optional<const char *> getReplacementType(StringRef Type) {
void DeprecatedIosBaseAliasesCheck::registerMatchers(MatchFinder *Finder) {
auto IoStateDecl = typedefDecl(hasAnyName(DeprecatedTypes)).bind("TypeDecl");
- auto IoStateType =
- qualType(hasDeclaration(IoStateDecl), unless(elaboratedType()));
+ auto IoStateType = typedefType(hasDeclaration(IoStateDecl));
Finder->addMatcher(typeLoc(loc(IoStateType)).bind("TypeLoc"), this);
}
@@ -43,12 +42,14 @@ void DeprecatedIosBaseAliasesCheck::check(
StringRef TypeName = Typedef->getName();
auto Replacement = getReplacementType(TypeName);
- const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("TypeLoc");
- SourceLocation IoStateLoc = TL->getBeginLoc();
+ TypeLoc TL = *Result.Nodes.getNodeAs<TypeLoc>("TypeLoc");
+ if (auto QTL = TL.getAs<QualifiedTypeLoc>())
+ TL = QTL.getUnqualifiedLoc();
+ SourceLocation IoStateLoc = TL.castAs<TypedefTypeLoc>().getNameLoc();
// Do not generate fixits for matches depending on template arguments and
// macro expansions.
- bool Fix = Replacement && !TL->getType()->isDependentType();
+ bool Fix = Replacement && !TL.getType()->isDependentType();
if (IoStateLoc.isMacroID()) {
IoStateLoc = SM.getSpellingLoc(IoStateLoc);
Fix = false;
diff --git a/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp
index c2db858..118e96a 100644
--- a/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp
@@ -395,16 +395,12 @@ void MacroToEnumCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) {
--CurrentFile->ConditionScopes;
}
-namespace {
-
template <size_t N>
-bool textEquals(const char (&Needle)[N], const char *HayStack) {
+static bool textEquals(const char (&Needle)[N], const char *HayStack) {
return StringRef{HayStack, N - 1} == Needle;
}
-template <size_t N> size_t len(const char (&)[N]) { return N - 1; }
-
-} // namespace
+template <size_t N> static size_t len(const char (&)[N]) { return N - 1; }
void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc,
PragmaIntroducerKind Introducer) {
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index deef358..ac8476b 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -16,14 +16,14 @@ using namespace clang::ast_matchers;
namespace clang::tidy::modernize {
-namespace {
-
-constexpr char ConstructorCall[] = "constructorCall";
-constexpr char ResetCall[] = "resetCall";
-constexpr char NewExpression[] = "newExpression";
-
-std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
- const LangOptions &Lang) {
+static constexpr char ConstructorCall[] = "constructorCall";
+static constexpr char DirectVar[] = "directVar";
+static constexpr char ResetCall[] = "resetCall";
+static constexpr char NewExpression[] = "newExpression";
+
+static std::string getNewExprName(const CXXNewExpr *NewExpr,
+ const SourceManager &SM,
+ const LangOptions &Lang) {
StringRef WrittenName = Lexer::getSourceText(
CharSourceRange::getTokenRange(
NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
@@ -34,8 +34,6 @@ std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
return WrittenName.str();
}
-} // namespace
-
const char MakeSmartPtrCheck::PointerType[] = "pointerType";
MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
@@ -81,18 +79,18 @@ void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
auto IsPlacement = hasAnyPlacementArg(anything());
Finder->addMatcher(
- traverse(
- TK_AsIs,
- cxxBindTemporaryExpr(has(ignoringParenImpCasts(
- cxxConstructExpr(
- hasType(getSmartPointerTypeMatcher()), argumentCountIs(1),
- hasArgument(
- 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
- equalsBoundNode(PointerType))))),
- CanCallCtor, unless(IsPlacement))
- .bind(NewExpression)),
- unless(isInTemplateInstantiation()))
- .bind(ConstructorCall))))),
+ traverse(TK_AsIs,
+ cxxConstructExpr(
+ anyOf(hasParent(cxxBindTemporaryExpr()),
+ hasParent(varDecl().bind(DirectVar))),
+ hasType(getSmartPointerTypeMatcher()), argumentCountIs(1),
+ hasArgument(
+ 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
+ equalsBoundNode(PointerType))))),
+ CanCallCtor, unless(IsPlacement))
+ .bind(NewExpression)),
+ unless(isInTemplateInstantiation()))
+ .bind(ConstructorCall)),
this);
Finder->addMatcher(
@@ -119,6 +117,7 @@ void MakeSmartPtrCheck::check(const MatchFinder::MatchResult &Result) {
SourceManager &SM = *Result.SourceManager;
const auto *Construct =
Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
+ const auto *DVar = Result.Nodes.getNodeAs<VarDecl>(DirectVar);
const auto *Reset = Result.Nodes.getNodeAs<CXXMemberCallExpr>(ResetCall);
const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType);
const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
@@ -141,13 +140,14 @@ void MakeSmartPtrCheck::check(const MatchFinder::MatchResult &Result) {
if (!Initializes && IgnoreDefaultInitialization)
return;
if (Construct)
- checkConstruct(SM, Result.Context, Construct, Type, New);
+ checkConstruct(SM, Result.Context, Construct, DVar, Type, New);
else if (Reset)
checkReset(SM, Result.Context, Reset, New);
}
void MakeSmartPtrCheck::checkConstruct(SourceManager &SM, ASTContext *Ctx,
const CXXConstructExpr *Construct,
+ const VarDecl *DVar,
const QualType *Type,
const CXXNewExpr *New) {
SourceLocation ConstructCallStart = Construct->getExprLoc();
@@ -190,9 +190,14 @@ void MakeSmartPtrCheck::checkConstruct(SourceManager &SM, ASTContext *Ctx,
ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
}
+ std::string FinalMakeSmartPtrFunctionName = MakeSmartPtrFunctionName.str();
+ if (DVar)
+ FinalMakeSmartPtrFunctionName =
+ ExprStr.str() + " = " + MakeSmartPtrFunctionName.str();
+
Diag << FixItHint::CreateReplacement(
CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
- MakeSmartPtrFunctionName);
+ FinalMakeSmartPtrFunctionName);
// If the smart_ptr is built with brace enclosed direct initialization, use
// parenthesis instead.
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h
index 02374dc..e2f9abe 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h
@@ -51,8 +51,8 @@ private:
const bool IgnoreDefaultInitialization;
void checkConstruct(SourceManager &SM, ASTContext *Ctx,
- const CXXConstructExpr *Construct, const QualType *Type,
- const CXXNewExpr *New);
+ const CXXConstructExpr *Construct, const VarDecl *DVar,
+ const QualType *Type, const CXXNewExpr *New);
void checkReset(SourceManager &SM, ASTContext *Ctx,
const CXXMemberCallExpr *Reset, const CXXNewExpr *New);
diff --git a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
index 1e271dfa..a54d072 100644
--- a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
@@ -77,8 +77,7 @@ AST_MATCHER_P(CXXRecordDecl, isMoveConstructibleInBoundCXXRecordDecl, StringRef,
static TypeMatcher notTemplateSpecConstRefType() {
return lValueReferenceType(
- pointee(unless(elaboratedType(namesType(templateSpecializationType()))),
- isConstQualified()));
+ pointee(unless(templateSpecializationType()), isConstQualified()));
}
static TypeMatcher nonConstValueType() {
diff --git a/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp b/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
index 24674a4..0c9e909 100644
--- a/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
@@ -19,9 +19,7 @@ using namespace clang::ast_matchers;
namespace clang::tidy::modernize {
-namespace {
-
-bool containsEscapes(StringRef HayStack, StringRef Escapes) {
+static bool containsEscapes(StringRef HayStack, StringRef Escapes) {
size_t BackSlash = HayStack.find('\\');
if (BackSlash == StringRef::npos)
return false;
@@ -35,16 +33,16 @@ bool containsEscapes(StringRef HayStack, StringRef Escapes) {
return true;
}
-bool isRawStringLiteral(StringRef Text) {
+static bool isRawStringLiteral(StringRef Text) {
// Already a raw string literal if R comes before ".
const size_t QuotePos = Text.find('"');
assert(QuotePos != StringRef::npos);
return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
}
-bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
- const StringLiteral *Literal,
- const CharsBitSet &DisallowedChars) {
+static bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
+ const StringLiteral *Literal,
+ const CharsBitSet &DisallowedChars) {
// FIXME: Handle L"", u8"", u"" and U"" literals.
if (!Literal->isOrdinary())
return false;
@@ -64,14 +62,12 @@ bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
return containsEscapes(Text, R"('\"?x01)");
}
-bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
+static bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
return Bytes.find(Delimiter.empty()
? std::string(R"lit()")lit")
: (")" + Delimiter + R"(")")) != StringRef::npos;
}
-} // namespace
-
RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
index 1ad31d3..f2142b8 100644
--- a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
@@ -48,7 +48,7 @@ void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isInStdNamespace());
- auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl));
+ auto AutoPtrType = hasCanonicalType(recordType(hasDeclaration(AutoPtrDecl)));
// std::auto_ptr<int> a;
// ^~~~~~~~~~~~~
@@ -58,11 +58,7 @@ void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
//
// std::auto_ptr<int> fn(std::auto_ptr<int>);
// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
- Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType,
- // Skip elaboratedType() as the named
- // type will match soon thereafter.
- unless(elaboratedType()))))
- .bind(AutoPtrTokenId),
+ Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType))).bind(AutoPtrTokenId),
this);
// using std::auto_ptr;
@@ -118,10 +114,13 @@ void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
}
SourceLocation AutoPtrLoc;
- if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
+ if (const auto *PTL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
+ auto TL = *PTL;
+ if (auto QTL = TL.getAs<QualifiedTypeLoc>())
+ TL = QTL.getUnqualifiedLoc();
// std::auto_ptr<int> i;
// ^
- if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>())
+ if (auto Loc = TL.getAs<TemplateSpecializationTypeLoc>())
AutoPtrLoc = Loc.getTemplateNameLoc();
} else if (const auto *D =
Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
diff --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
index ff0b321..4721282 100644
--- a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
@@ -168,19 +168,6 @@ static DeclarationName getName(const DeclRefExpr &D) {
return D.getDecl()->getDeclName();
}
-static bool isNamedType(const ElaboratedTypeLoc &ETL) {
- if (const auto *TFT =
- ETL.getNamedTypeLoc().getTypePtr()->getAs<TypedefType>()) {
- const TypedefNameDecl *Decl = TFT->getDecl();
- return Decl->getDeclName().isIdentifier() && Decl->getName() == "type";
- }
- return false;
-}
-
-static bool isNamedType(const DependentNameTypeLoc &DTL) {
- return DTL.getTypePtr()->getIdentifier()->getName() == "type";
-}
-
namespace {
AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES(
DeclRefExpr, DependentScopeDeclRefExpr)) {
@@ -188,25 +175,20 @@ AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES(
return Ident && Ident->isStr("value");
}
-AST_POLYMORPHIC_MATCHER(isType,
- AST_POLYMORPHIC_SUPPORTED_TYPES(ElaboratedTypeLoc,
- DependentNameTypeLoc)) {
- return Node.getBeginLoc().isValid() && isNamedType(Node);
+AST_MATCHER(TypeLoc, isType) {
+ if (auto TL = Node.getAs<TypedefTypeLoc>()) {
+ const auto *TD = TL.getDecl();
+ return TD->getDeclName().isIdentifier() && TD->getName() == "type";
+ }
+ if (auto TL = Node.getAs<DependentNameTypeLoc>())
+ return TL.getTypePtr()->getIdentifier()->getName() == "type";
+ return false;
}
} // namespace
static constexpr char Bind[] = "";
void TypeTraitsCheck::registerMatchers(MatchFinder *Finder) {
- const ast_matchers::internal::VariadicDynCastAllOfMatcher<
- Stmt,
- DependentScopeDeclRefExpr>
- dependentScopeDeclRefExpr; // NOLINT(readability-identifier-naming)
- const ast_matchers::internal::VariadicDynCastAllOfMatcher<
- TypeLoc,
- DependentNameTypeLoc>
- dependentNameTypeLoc; // NOLINT(readability-identifier-naming)
-
// Only register matchers for trait<...>::value in c++17 mode.
if (getLangOpts().CPlusPlus17) {
Finder->addMatcher(mapAnyOf(declRefExpr, dependentScopeDeclRefExpr)
@@ -214,10 +196,7 @@ void TypeTraitsCheck::registerMatchers(MatchFinder *Finder) {
.bind(Bind),
this);
}
- Finder->addMatcher(mapAnyOf(elaboratedTypeLoc, dependentNameTypeLoc)
- .with(isType())
- .bind(Bind),
- this);
+ Finder->addMatcher(typeLoc(isType()).bind(Bind), this);
}
static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND,
@@ -226,14 +205,11 @@ static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND,
Set.contains(ND->getName());
}
-static bool checkTemplatedDecl(const NestedNameSpecifier *NNS,
+static bool checkTemplatedDecl(NestedNameSpecifier NNS,
const llvm::StringSet<> &Set) {
- if (!NNS)
+ if (NNS.getKind() != NestedNameSpecifier::Kind::Type)
return false;
- const Type *NNST = NNS->getAsType();
- if (!NNST)
- return false;
- const auto *TST = NNST->getAs<TemplateSpecializationType>();
+ const auto *TST = NNS.getAsType()->getAs<TemplateSpecializationType>();
if (!TST)
return false;
if (const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) {
@@ -250,8 +226,8 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
auto EmitValueWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc,
SourceLocation EndLoc) {
SourceLocation TemplateNameEndLoc;
- if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
- !TSTL.isNull())
+ if (auto TSTL =
+ QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>())
TemplateNameEndLoc = Lexer::getLocForEndOfToken(
TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
Result.Context->getLangOpts());
@@ -274,8 +250,8 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
SourceLocation EndLoc,
SourceLocation TypenameLoc) {
SourceLocation TemplateNameEndLoc;
- if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
- !TSTL.isNull())
+ if (auto TSTL =
+ QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>())
TemplateNameEndLoc = Lexer::getLocForEndOfToken(
TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
Result.Context->getLangOpts());
@@ -301,23 +277,21 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
if (!DRE->hasQualifier())
return;
if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
- DRE->getQualifier()->getAsRecordDecl())) {
+ DRE->getQualifier().getAsRecordDecl())) {
if (isNamedDeclInStdTraitsSet(CTSD, ValueTraits))
EmitValueWarning(DRE->getQualifierLoc(), DRE->getEndLoc());
}
return;
}
- if (const auto *ETL = Result.Nodes.getNodeAs<ElaboratedTypeLoc>(Bind)) {
- const NestedNameSpecifierLoc QualLoc = ETL->getQualifierLoc();
- const auto *NNS = QualLoc.getNestedNameSpecifier();
- if (!NNS)
- return;
+ if (const auto *TL = Result.Nodes.getNodeAs<TypedefTypeLoc>(Bind)) {
+ const NestedNameSpecifierLoc QualLoc = TL->getQualifierLoc();
+ NestedNameSpecifier NNS = QualLoc.getNestedNameSpecifier();
if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
- NNS->getAsRecordDecl())) {
+ NNS.getAsRecordDecl())) {
if (isNamedDeclInStdTraitsSet(CTSD, TypeTraits))
- EmitTypeWarning(ETL->getQualifierLoc(), ETL->getEndLoc(),
- ETL->getElaboratedKeywordLoc());
+ EmitTypeWarning(TL->getQualifierLoc(), TL->getEndLoc(),
+ TL->getElaboratedKeywordLoc());
}
return;
}
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
index f4b6308..aedfda8 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
@@ -186,16 +186,14 @@ TypeMatcher nestedIterator() {
/// declarations and which name standard iterators for standard containers.
TypeMatcher iteratorFromUsingDeclaration() {
auto HasIteratorDecl = hasDeclaration(namedDecl(hasStdIteratorName()));
- // Types resulting from using declarations are represented by elaboratedType.
- return elaboratedType(
- // Unwrap the nested name specifier to test for one of the standard
- // containers.
- hasQualifier(specifiesType(templateSpecializationType(hasDeclaration(
- namedDecl(hasStdContainerName(), isInStdNamespace()))))),
- // the named type is what comes after the final '::' in the type. It
- // should name one of the standard iterator names.
- namesType(
- anyOf(typedefType(HasIteratorDecl), recordType(HasIteratorDecl))));
+ // Unwrap the nested name specifier to test for one of the standard
+ // containers.
+ auto Qualifier = hasQualifier(specifiesType(templateSpecializationType(
+ hasDeclaration(namedDecl(hasStdContainerName(), isInStdNamespace())))));
+ // the named type is what comes after the final '::' in the type. It should
+ // name one of the standard iterator names.
+ return anyOf(typedefType(HasIteratorDecl, Qualifier),
+ recordType(HasIteratorDecl, Qualifier));
}
/// This matcher returns declaration statements that contain variable
@@ -336,14 +334,14 @@ void UseAutoCheck::replaceIterators(const DeclStmt *D, ASTContext *Context) {
static void ignoreTypeLocClasses(
TypeLoc &Loc,
- std::initializer_list<TypeLoc::TypeLocClass> const &LocClasses) {
+ const std::initializer_list<TypeLoc::TypeLocClass> &LocClasses) {
while (llvm::is_contained(LocClasses, Loc.getTypeLocClass()))
Loc = Loc.getNextTypeLoc();
}
static bool isMultiLevelPointerToTypeLocClasses(
TypeLoc Loc,
- std::initializer_list<TypeLoc::TypeLocClass> const &LocClasses) {
+ const std::initializer_list<TypeLoc::TypeLocClass> &LocClasses) {
ignoreTypeLocClasses(Loc, {TypeLoc::Paren, TypeLoc::Qualified});
TypeLoc::TypeLocClass TLC = Loc.getTypeLocClass();
if (TLC != TypeLoc::Pointer && TLC != TypeLoc::MemberPointer)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
index e9b96c4..c4a64be 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
@@ -8,6 +8,7 @@
#include "UseConstraintsCheck.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
@@ -60,9 +61,11 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) {
Keyword != ElaboratedTypeKeyword::None)) {
return std::nullopt;
}
- TheType = Dep.getQualifierLoc().getTypeLoc();
+ TheType = Dep.getQualifierLoc().getAsTypeLoc();
if (TheType.isNull())
return std::nullopt;
+ } else {
+ return std::nullopt;
}
if (const auto SpecializationLoc =
@@ -78,6 +81,13 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) {
if (!TD || TD->getName() != "enable_if")
return std::nullopt;
+ assert(!TD->getTemplateParameters()->empty() &&
+ "found template with no template parameters?");
+ const auto *FirstParam = dyn_cast<NonTypeTemplateParmDecl>(
+ TD->getTemplateParameters()->getParam(0));
+ if (!FirstParam || !FirstParam->getType()->isBooleanType())
+ return std::nullopt;
+
int NumArgs = SpecializationLoc.getNumArgs();
if (NumArgs != 1 && NumArgs != 2)
return std::nullopt;
@@ -89,9 +99,6 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) {
static std::optional<TemplateSpecializationTypeLoc>
matchEnableIfSpecializationImplTrait(TypeLoc TheType) {
- if (const auto Elaborated = TheType.getAs<ElaboratedTypeLoc>())
- TheType = Elaborated.getNamedTypeLoc();
-
if (const auto SpecializationLoc =
TheType.getAs<TemplateSpecializationTypeLoc>()) {
@@ -108,6 +115,13 @@ matchEnableIfSpecializationImplTrait(TypeLoc TheType) {
if (!Specialization->isTypeAlias())
return std::nullopt;
+ assert(!TD->getTemplateParameters()->empty() &&
+ "found template with no template parameters?");
+ const auto *FirstParam = dyn_cast<NonTypeTemplateParmDecl>(
+ TD->getTemplateParameters()->getParam(0));
+ if (!FirstParam || !FirstParam->getType()->isBooleanType())
+ return std::nullopt;
+
if (const auto *AliasedType =
dyn_cast<DependentNameType>(Specialization->getAliasedType())) {
ElaboratedTypeKeyword Keyword = AliasedType->getKeyword();
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
index aaf24ea..ee49d8a 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
@@ -164,10 +164,10 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
auto CallEmplacy = cxxMemberCallExpr(
hasDeclaration(
functionDecl(hasAnyNameIgnoringTemplates(EmplacyFunctions))),
- on(hasTypeOrPointeeType(hasCanonicalType(hasDeclaration(
- has(typedefNameDecl(hasName("value_type"),
- hasType(type(hasUnqualifiedDesugaredType(
- recordType().bind("value_type")))))))))));
+ on(hasTypeOrPointeeType(
+ hasCanonicalType(hasDeclaration(has(typedefNameDecl(
+ hasName("value_type"),
+ hasType(hasCanonicalType(recordType().bind("value_type"))))))))));
// We can't replace push_backs of smart pointer because
// if emplacement fails (f.e. bad_alloc in vector) we will have leak of
@@ -241,17 +241,16 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
auto HasConstructExprWithValueTypeType =
has(ignoringImplicit(cxxConstructExpr(
- SoughtConstructExpr, hasType(type(hasUnqualifiedDesugaredType(
- type(equalsBoundNode("value_type"))))))));
-
- auto HasBracedInitListWithValueTypeType =
- anyOf(allOf(HasConstructInitListExpr,
- has(initListExpr(hasType(type(hasUnqualifiedDesugaredType(
- type(equalsBoundNode("value_type")))))))),
- has(cxxBindTemporaryExpr(
- HasConstructInitListExpr,
- has(initListExpr(hasType(type(hasUnqualifiedDesugaredType(
- type(equalsBoundNode("value_type"))))))))));
+ SoughtConstructExpr,
+ hasType(hasCanonicalType(type(equalsBoundNode("value_type")))))));
+
+ auto HasBracedInitListWithValueTypeType = anyOf(
+ allOf(HasConstructInitListExpr,
+ has(initListExpr(hasType(
+ hasCanonicalType(type(equalsBoundNode("value_type"))))))),
+ has(cxxBindTemporaryExpr(HasConstructInitListExpr,
+ has(initListExpr(hasType(hasCanonicalType(
+ type(equalsBoundNode("value_type")))))))));
auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument(
materializeTemporaryExpr(
@@ -289,19 +288,17 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
this);
Finder->addMatcher(
- traverse(
- TK_AsIs,
- cxxMemberCallExpr(
- CallEmplacy,
- on(hasType(cxxRecordDecl(has(typedefNameDecl(
- hasName("value_type"),
- hasType(type(
- hasUnqualifiedDesugaredType(recordType(hasDeclaration(
- cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>(
- TupleTypes.begin(), TupleTypes.end()))))))))))))),
- has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
- unless(isInTemplateInstantiation()))
- .bind("emplacy_call")),
+ traverse(TK_AsIs,
+ cxxMemberCallExpr(
+ CallEmplacy,
+ on(hasType(cxxRecordDecl(has(typedefNameDecl(
+ hasName("value_type"),
+ hasType(hasCanonicalType(recordType(hasDeclaration(
+ cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>(
+ TupleTypes.begin(), TupleTypes.end())))))))))))),
+ has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
+ unless(isInTemplateInstantiation()))
+ .bind("emplacy_call")),
this);
}
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index 52e9a9f..c74db0e 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -28,8 +28,8 @@ static bool isLockGuardDecl(const NamedDecl *Decl) {
}
static bool isLockGuard(const QualType &Type) {
- if (const auto *Record = Type->getAs<RecordType>())
- if (const RecordDecl *Decl = Record->getDecl())
+ if (const auto *Record = Type->getAsCanonical<RecordType>())
+ if (const RecordDecl *Decl = Record->getOriginalDecl())
return isLockGuardDecl(Decl);
if (const auto *TemplateSpecType = Type->getAs<TemplateSpecializationType>())
@@ -89,17 +89,6 @@ findLocksInCompoundStmt(const CompoundStmt *Block,
return LockGuardGroups;
}
-static TemplateSpecializationTypeLoc
-getTemplateLockGuardTypeLoc(const TypeSourceInfo *SourceInfo) {
- const TypeLoc Loc = SourceInfo->getTypeLoc();
-
- const auto ElaboratedLoc = Loc.getAs<ElaboratedTypeLoc>();
- if (!ElaboratedLoc)
- return {};
-
- return ElaboratedLoc.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>();
-}
-
// Find the exact source range of the 'lock_guard' token
static SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) {
const TypeLoc LockGuardTypeLoc = SourceInfo->getTypeLoc();
@@ -110,7 +99,7 @@ static SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) {
// Find the exact source range of the 'lock_guard' name token
static SourceRange getLockGuardNameRange(const TypeSourceInfo *SourceInfo) {
const TemplateSpecializationTypeLoc TemplateLoc =
- getTemplateLockGuardTypeLoc(SourceInfo);
+ SourceInfo->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
if (!TemplateLoc)
return {};
@@ -136,11 +125,11 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
const auto LockGuardClassDecl =
namedDecl(hasName("lock_guard"), isInStdNamespace());
- const auto LockGuardType = qualType(anyOf(
- hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(LockGuardClassDecl))),
- elaboratedType(namesType(hasUnqualifiedDesugaredType(
- templateSpecializationType(hasDeclaration(LockGuardClassDecl)))))));
+ const auto LockGuardType =
+ qualType(anyOf(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(LockGuardClassDecl))),
+ hasUnqualifiedDesugaredType(templateSpecializationType(
+ hasDeclaration(LockGuardClassDecl)))));
const auto LockVarDecl = varDecl(hasType(LockGuardType));
@@ -165,18 +154,16 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
if (WarnOnUsingAndTypedef) {
// Match 'typedef std::lock_guard<std::mutex> Lock'
Finder->addMatcher(typedefDecl(unless(isExpansionInSystemHeader()),
- hasUnderlyingType(LockGuardType))
+ hasType(hasUnderlyingType(LockGuardType)))
.bind("lock-guard-typedef"),
this);
// Match 'using Lock = std::lock_guard<std::mutex>'
- Finder->addMatcher(
- typeAliasDecl(
- unless(isExpansionInSystemHeader()),
- hasType(elaboratedType(namesType(templateSpecializationType(
- hasDeclaration(LockGuardClassDecl))))))
- .bind("lock-guard-using-alias"),
- this);
+ Finder->addMatcher(typeAliasDecl(unless(isExpansionInSystemHeader()),
+ hasType(templateSpecializationType(
+ hasDeclaration(LockGuardClassDecl))))
+ .bind("lock-guard-using-alias"),
+ this);
// Match 'using std::lock_guard'
Finder->addMatcher(
@@ -288,8 +275,8 @@ void UseScopedLockCheck::diagOnSourceInfo(
const ast_matchers::MatchFinder::MatchResult &Result) {
const TypeLoc TL = LockGuardSourceInfo->getTypeLoc();
- if (const auto ElaboratedTL = TL.getAs<ElaboratedTypeLoc>()) {
- auto Diag = diag(ElaboratedTL.getBeginLoc(), UseScopedLockMessage);
+ if (const auto TTL = TL.getAs<TemplateSpecializationTypeLoc>()) {
+ auto Diag = diag(TTL.getBeginLoc(), UseScopedLockMessage);
const SourceRange LockGuardRange =
getLockGuardNameRange(LockGuardSourceInfo);
diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
index ced4825..82f6409 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
@@ -64,66 +64,65 @@ public:
return false;
}
- bool TraverseTypeLoc(TypeLoc TL, bool Elaborated = false) {
+ bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
if (TL.isNull())
return true;
- if (!Elaborated) {
- switch (TL.getTypeLocClass()) {
- case TypeLoc::Record:
- if (visitUnqualName(
- TL.getAs<RecordTypeLoc>().getTypePtr()->getDecl()->getName()))
- return false;
+ switch (TL.getTypeLocClass()) {
+ case TypeLoc::InjectedClassName:
+ case TypeLoc::Record:
+ case TypeLoc::Enum: {
+ auto TTL = TL.getAs<TagTypeLoc>();
+ const auto *T = TTL.getTypePtr();
+ if (T->getKeyword() != ElaboratedTypeKeyword::None ||
+ TTL.getQualifierLoc())
break;
- case TypeLoc::Enum:
- if (visitUnqualName(
- TL.getAs<EnumTypeLoc>().getTypePtr()->getDecl()->getName()))
- return false;
- break;
- case TypeLoc::TemplateSpecialization:
- if (visitUnqualName(TL.getAs<TemplateSpecializationTypeLoc>()
- .getTypePtr()
- ->getTemplateName()
- .getAsTemplateDecl()
- ->getName()))
- return false;
- break;
- case TypeLoc::Typedef:
- if (visitUnqualName(
- TL.getAs<TypedefTypeLoc>().getTypePtr()->getDecl()->getName()))
- return false;
+ if (visitUnqualName(T->getOriginalDecl()->getName()))
+ return false;
+ break;
+ }
+ case TypeLoc::TemplateSpecialization: {
+ auto TTL = TL.getAs<TemplateSpecializationTypeLoc>();
+ const auto *T = TTL.getTypePtr();
+ if (T->getKeyword() != ElaboratedTypeKeyword::None ||
+ TTL.getQualifierLoc())
break;
- case TypeLoc::Using:
- if (visitUnqualName(TL.getAs<UsingTypeLoc>()
- .getTypePtr()
- ->getFoundDecl()
- ->getName()))
- return false;
+ if (visitUnqualName(T->getTemplateName().getAsTemplateDecl()->getName()))
+ return false;
+ break;
+ }
+ case TypeLoc::Typedef: {
+ auto TTL = TL.getAs<TypedefTypeLoc>();
+ const auto *T = TTL.getTypePtr();
+ if (T->getKeyword() != ElaboratedTypeKeyword::None ||
+ TTL.getQualifierLoc())
break;
- default:
+ if (visitUnqualName(T->getDecl()->getName()))
+ return false;
+ break;
+ }
+ case TypeLoc::Using: {
+ auto TTL = TL.getAs<UsingTypeLoc>();
+ const auto *T = TTL.getTypePtr();
+ if (T->getKeyword() != ElaboratedTypeKeyword::None ||
+ TTL.getQualifierLoc())
break;
- }
+ if (visitUnqualName(T->getDecl()->getName()))
+ return false;
+ break;
+ }
+ default:
+ break;
}
- return RecursiveASTVisitor<UnqualNameVisitor>::TraverseTypeLoc(TL);
+ return RecursiveASTVisitor<UnqualNameVisitor>::TraverseTypeLoc(
+ TL, TraverseQualifier);
}
// Replace the base method in order to call our own
// TraverseTypeLoc().
- bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) {
- return TraverseTypeLoc(TL.getUnqualifiedLoc());
- }
-
- // Replace the base version to inform TraverseTypeLoc that the type is
- // elaborated.
- bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- if (TL.getQualifierLoc() &&
- !TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()))
- return false;
- const auto *T = TL.getTypePtr();
- return TraverseTypeLoc(TL.getNamedTypeLoc(),
- T->getKeyword() != ElaboratedTypeKeyword::None ||
- T->getQualifier());
+ bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL, bool TraverseQualifier) {
+ return TraverseTypeLoc(TL.getUnqualifiedLoc(), TraverseQualifier);
}
bool VisitDeclRefExpr(DeclRefExpr *S) {
diff --git a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
index a053c07..2373a26 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
@@ -37,15 +37,13 @@ void UseTransparentFunctorsCheck::registerMatchers(MatchFinder *Finder) {
// Non-transparent functor mentioned as a template parameter. FIXIT.
Finder->addMatcher(
- loc(qualType(
- unless(elaboratedType()),
- hasDeclaration(classTemplateSpecializationDecl(
- unless(hasAnyTemplateArgument(templateArgument(refersToType(
- qualType(pointsTo(qualType(isAnyCharacter()))))))),
- hasAnyTemplateArgument(
- templateArgument(refersToType(qualType(hasDeclaration(
- TransparentFunctors))))
- .bind("Functor"))))))
+ loc(qualType(hasDeclaration(classTemplateSpecializationDecl(
+ unless(hasAnyTemplateArgument(templateArgument(refersToType(
+ qualType(pointsTo(qualType(isAnyCharacter()))))))),
+ hasAnyTemplateArgument(
+ templateArgument(refersToType(qualType(
+ hasDeclaration(TransparentFunctors))))
+ .bind("Functor"))))))
.bind("FunctorParentLoc"),
this);
diff --git a/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp b/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp
index bd9bdd1..8e4ed41 100644
--- a/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp
@@ -29,12 +29,13 @@
using namespace clang::ast_matchers;
namespace clang::tidy::objc {
-namespace {
static constexpr StringRef WeakText = "__weak";
static constexpr StringRef StrongText = "__strong";
static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained";
+namespace {
+
/// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference
/// Objective-C object (or block) variables or fields whose object lifetimes
/// are not __unsafe_unretained.
@@ -49,6 +50,8 @@ AST_POLYMORPHIC_MATCHER(isObjCManagedLifetime,
QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone;
}
+} // namespace
+
static std::optional<FixItHint>
fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range,
StringRef Ownership) {
@@ -93,8 +96,6 @@ fixItHintForVarDecl(const VarDecl *VD, const SourceManager &SM,
return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained ");
}
-} // namespace
-
void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
traverse(
diff --git a/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp b/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp
index ffbdb02..01ee4d5 100644
--- a/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp
@@ -27,11 +27,14 @@ enum NamingStyle {
CategoryProperty = 2,
};
+} // namespace
+
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
/// 'camelCase' or 'abc_camelCase'. For other cases the users need to
/// come up with a proper name by their own.
/// FIXME: provide fix for snake_case to snakeCase
-FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
+static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl,
+ NamingStyle Style) {
auto Name = Decl->getName();
auto NewName = Decl->getName().str();
size_t Index = 0;
@@ -50,7 +53,7 @@ FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
return {};
}
-std::string validPropertyNameRegex(bool UsedInMatcher) {
+static std::string validPropertyNameRegex(bool UsedInMatcher) {
// Allow any of these names:
// foo
// fooBar
@@ -72,13 +75,13 @@ std::string validPropertyNameRegex(bool UsedInMatcher) {
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
}
-bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
+static bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
auto RegexExp =
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
return RegexExp.match(PropertyName);
}
-bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
+static bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
size_t Start = PropertyName.find_first_of('_');
assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
auto Prefix = PropertyName.substr(0, Start);
@@ -88,7 +91,6 @@ bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
return RegexExp.match(PropertyName.substr(Start + 1));
}
-} // namespace
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(objcPropertyDecl(
diff --git a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp
index 7022e9d..1c01899 100644
--- a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp
@@ -42,11 +42,11 @@ void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) {
// A matcher for a `DstT::DstT(const Src&)` where DstT also has a
// `DstT::DstT(Src&&)`.
const auto LValueRefCtor = cxxConstructorDecl(
- hasParameter(0,
- hasType(lValueReferenceType(pointee(type().bind("SrcT"))))),
+ hasParameter(0, hasType(hasCanonicalType(
+ lValueReferenceType(pointee(type().bind("SrcT")))))),
ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl(
- hasParameter(0, hasType(rValueReferenceType(
- pointee(type(equalsBoundNode("SrcT")))))))))));
+ hasParameter(0, hasType(hasCanonicalType(rValueReferenceType(
+ pointee(type(equalsBoundNode("SrcT"))))))))))));
// A matcher for `DstT::DstT(const Src&&)`, which typically comes from an
// instantiation of `template <typename U> DstT::DstT(U&&)`.
diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 120f7fb..c413090 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -17,7 +17,6 @@
#include <optional>
namespace clang::tidy::performance {
-namespace {
using namespace ::clang::ast_matchers;
using llvm::StringRef;
@@ -30,8 +29,8 @@ static constexpr StringRef MethodDeclId = "methodDecl";
static constexpr StringRef FunctionDeclId = "functionDecl";
static constexpr StringRef OldVarDeclId = "oldVarDecl";
-void recordFixes(const VarDecl &Var, ASTContext &Context,
- DiagnosticBuilder &Diagnostic) {
+static void recordFixes(const VarDecl &Var, ASTContext &Context,
+ DiagnosticBuilder &Diagnostic) {
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
if (!Var.getType().isLocalConstQualified()) {
if (std::optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
@@ -40,8 +39,8 @@ void recordFixes(const VarDecl &Var, ASTContext &Context,
}
}
-std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
- SourceManager &SM) {
+static std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
+ SourceManager &SM) {
bool Invalid = false;
const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
if (Invalid) {
@@ -51,8 +50,8 @@ std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
}
-void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
- DiagnosticBuilder &Diagnostic) {
+static void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
+ DiagnosticBuilder &Diagnostic) {
auto &SM = Context.getSourceManager();
// Attempt to remove trailing comments as well.
auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
@@ -74,6 +73,8 @@ void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
}
}
+namespace {
+
AST_MATCHER_FUNCTION_P(StatementMatcher,
isRefReturningMethodCallWithConstOverloads,
std::vector<StringRef>, ExcludedContainerTypes) {
@@ -130,6 +131,8 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst,
hasUnaryOperand(OldVarDeclRef)))));
}
+} // namespace
+
// This checks that the variable itself is only used as const, and also makes
// sure that it does not reference another variable that could be modified in
// the BlockStmt. It does this by checking the following:
@@ -180,13 +183,13 @@ static bool isInitializingVariableImmutable(
return false;
}
-bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
- ASTContext &Context) {
+static bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
+ ASTContext &Context) {
return allDeclRefExprs(Var, BlockStmt, Context).empty();
}
-const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
- ASTContext &Context) {
+static const SubstTemplateTypeParmType *
+getSubstitutedType(const QualType &Type, ASTContext &Context) {
auto Matches = match(
qualType(anyOf(substTemplateTypeParmType().bind("subst"),
hasDescendant(substTemplateTypeParmType().bind("subst")))),
@@ -194,9 +197,9 @@ const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
return selectFirst<SubstTemplateTypeParmType>("subst", Matches);
}
-bool differentReplacedTemplateParams(const QualType &VarType,
- const QualType &InitializerType,
- ASTContext &Context) {
+static bool differentReplacedTemplateParams(const QualType &VarType,
+ const QualType &InitializerType,
+ ASTContext &Context) {
if (const SubstTemplateTypeParmType *VarTmplType =
getSubstitutedType(VarType, Context)) {
if (const SubstTemplateTypeParmType *InitializerTmplType =
@@ -212,8 +215,8 @@ bool differentReplacedTemplateParams(const QualType &VarType,
return false;
}
-QualType constructorArgumentType(const VarDecl *OldVar,
- const BoundNodes &Nodes) {
+static QualType constructorArgumentType(const VarDecl *OldVar,
+ const BoundNodes &Nodes) {
if (OldVar) {
return OldVar->getType();
}
@@ -224,8 +227,6 @@ QualType constructorArgumentType(const VarDecl *OldVar,
return MethodDecl->getReturnType();
}
-} // namespace
-
UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
index fbd2ba6..c1aa52b 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -21,16 +21,14 @@ using namespace clang::ast_matchers;
namespace clang::tidy::performance {
-namespace {
-
-std::string paramNameOrIndex(StringRef Name, size_t Index) {
+static std::string paramNameOrIndex(StringRef Name, size_t Index) {
return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
: llvm::Twine('\'') + Name + llvm::Twine('\''))
.str();
}
-bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
- ASTContext &Context) {
+static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
+ ASTContext &Context) {
auto Matches = match(
traverse(TK_AsIs,
decl(forEachDescendant(declRefExpr(
@@ -41,8 +39,6 @@ bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
return Matches.empty();
}
-} // namespace
-
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
diff --git a/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp b/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp
index 3b4d65b..5a3c9a4 100644
--- a/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp
@@ -15,10 +15,11 @@ namespace clang::tidy::portability {
void StdAllocatorConstCheck::registerMatchers(MatchFinder *Finder) {
// Match std::allocator<const T>.
- auto AllocatorConst =
+ auto AllocatorConst = qualType(hasCanonicalType(
recordType(hasDeclaration(classTemplateSpecializationDecl(
hasName("::std::allocator"),
- hasTemplateArgument(0, refersToType(qualType(isConstQualified()))))));
+ hasTemplateArgument(0,
+ refersToType(qualType(isConstQualified()))))))));
auto HasContainerName =
hasAnyName("::std::vector", "::std::deque", "::std::list",
@@ -31,8 +32,10 @@ void StdAllocatorConstCheck::registerMatchers(MatchFinder *Finder) {
// aren't caught.
Finder->addMatcher(
typeLoc(
- templateSpecializationTypeLoc(),
- loc(hasUnqualifiedDesugaredType(anyOf(
+ anyOf(templateSpecializationTypeLoc(),
+ qualifiedTypeLoc(
+ hasUnqualifiedLoc(templateSpecializationTypeLoc()))),
+ loc(qualType(anyOf(
recordType(hasDeclaration(classTemplateSpecializationDecl(
HasContainerName,
anyOf(
diff --git a/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.h b/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.h
index d22d1aa..87702af 100644
--- a/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.h
+++ b/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.h
@@ -23,6 +23,9 @@ class StdAllocatorConstCheck : public ClangTidyCheck {
public:
StdAllocatorConstCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
diff --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
index ce736a8..c3f8106 100644
--- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -89,10 +89,6 @@ AST_MATCHER(Expr, usedInBooleanContext) {
return Result;
}
-AST_MATCHER(CXXConstructExpr, isDefaultConstruction) {
- return Node.getConstructor()->isDefaultConstructor();
-}
-
AST_MATCHER(QualType, isIntegralType) {
return Node->isIntegralType(Finder->getASTContext());
}
@@ -110,6 +106,25 @@ AST_MATCHER_P(UserDefinedLiteral, hasLiteral,
return false;
}
+AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl,
+ clang::ast_matchers::internal::Matcher<CXXMethodDecl>,
+ InnerMatcher) {
+ return InnerMatcher.matches(*Node.getCanonicalDecl(), Finder, Builder);
+}
+
+AST_POLYMORPHIC_MATCHER_P(
+ matchMemberName,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(MemberExpr, CXXDependentScopeMemberExpr),
+ std::string, MemberName) {
+ if (const auto *E = dyn_cast<MemberExpr>(&Node))
+ return E->getMemberDecl()->getName() == MemberName;
+
+ if (const auto *E = dyn_cast<CXXDependentScopeMemberExpr>(&Node))
+ return E->getMember().getAsString() == MemberName;
+
+ return false;
+}
+
} // namespace
using utils::isBinaryOrTernary;
@@ -140,9 +155,10 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
const auto ValidContainerNonTemplateType =
qualType(hasUnqualifiedDesugaredType(
recordType(hasDeclaration(ValidContainerRecord))));
- const auto ValidContainerTemplateType =
- qualType(hasUnqualifiedDesugaredType(templateSpecializationType(
- hasDeclaration(classTemplateDecl(has(ValidContainerRecord))))));
+ const auto ValidContainerTemplateType = qualType(hasUnqualifiedDesugaredType(
+ anyOf(templateSpecializationType(
+ hasDeclaration(classTemplateDecl(has(ValidContainerRecord)))),
+ injectedClassNameType(hasDeclaration(ValidContainerRecord)))));
const auto ValidContainer = qualType(
anyOf(ValidContainerNonTemplateType, ValidContainerTemplateType));
@@ -155,6 +171,9 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
.bind("SizeBinaryOp")),
usedInBooleanContext());
+ const auto NotInEmptyMethodOfContainer = unless(
+ forCallable(cxxMethodDecl(hasCanonicalDecl(equalsBoundNode("empty")))));
+
Finder->addMatcher(
cxxMemberCallExpr(
argumentCountIs(0),
@@ -164,25 +183,23 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
.bind("MemberCallObject")),
callee(
cxxMethodDecl(hasAnyName("size", "length")).bind("SizeMethod")),
- WrongUse,
- unless(hasAncestor(
- cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+ WrongUse, NotInEmptyMethodOfContainer)
.bind("SizeCallExpr"),
this);
Finder->addMatcher(
- callExpr(argumentCountIs(0),
- has(cxxDependentScopeMemberExpr(
- hasObjectExpression(
- expr(anyOf(hasType(ValidContainer),
- hasType(pointsTo(ValidContainer)),
- hasType(references(ValidContainer))))
- .bind("MemberCallObject")),
- anyOf(hasMemberName("size"), hasMemberName("length")))
- .bind("DependentExpr")),
- WrongUse,
- unless(hasAncestor(
- cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+ callExpr(
+ argumentCountIs(0),
+ has(mapAnyOf(memberExpr, cxxDependentScopeMemberExpr)
+ .with(
+ hasObjectExpression(
+ expr(anyOf(hasType(ValidContainer),
+ hasType(pointsTo(ValidContainer)),
+ hasType(references(ValidContainer))))
+ .bind("MemberCallObject")),
+ anyOf(matchMemberName("size"), matchMemberName("length")))
+ .bind("MemberExpr")),
+ WrongUse, NotInEmptyMethodOfContainer)
.bind("SizeCallExpr"),
this);
@@ -190,7 +207,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
const auto WrongComparend =
anyOf(stringLiteral(hasSize(0)),
userDefinedLiteral(hasLiteral(stringLiteral(hasSize(0)))),
- cxxConstructExpr(isDefaultConstruction()),
+ cxxConstructExpr(argumentCountIs(0)),
cxxUnresolvedConstructExpr(argumentCountIs(0)));
// Match the object being compared.
const auto STLArg =
@@ -217,8 +234,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
hasAnyOperatorName("==", "!="), hasOperands(WrongComparend, STLArg),
unless(allOf(hasLHS(hasType(ExcludedComparisonTypesMatcher)),
hasRHS(hasType(SameExcludedComparisonTypesMatcher)))),
- unless(hasAncestor(
- cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+ NotInEmptyMethodOfContainer)
.bind("BinCmp"),
this);
}
@@ -238,9 +254,12 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
? MemberCallObject
: (Pointee ? Pointee : Result.Nodes.getNodeAs<Expr>("STLObject"));
FixItHint Hint;
- std::string ReplacementText = std::string(
- Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()),
- *Result.SourceManager, getLangOpts()));
+ std::string ReplacementText =
+ E->isImplicitCXXThis()
+ ? ""
+ : std::string(Lexer::getSourceText(
+ CharSourceRange::getTokenRange(E->getSourceRange()),
+ *Result.SourceManager, getLangOpts()));
const auto *OpCallExpr = dyn_cast<CXXOperatorCallExpr>(E);
if (isBinaryOrTernary(E) || isa<UnaryOperator>(E) ||
(OpCallExpr && (OpCallExpr->getOperator() == OO_Star))) {
@@ -251,6 +270,8 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
// This can happen if the object is a smart pointer. Don't add anything
// because a '->' is already there (PR#51776), just call the method.
ReplacementText += "empty()";
+ } else if (E->isImplicitCXXThis()) {
+ ReplacementText += "empty()";
} else if (E->getType()->isPointerType())
ReplacementText += "->empty()";
else
@@ -377,9 +398,12 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
Diag << SizeMethod;
else if (const auto *DependentExpr =
Result.Nodes.getNodeAs<CXXDependentScopeMemberExpr>(
- "DependentExpr"))
+ "MemberExpr"))
Diag << DependentExpr->getMember();
- else
+ else if (const auto *ME =
+ Result.Nodes.getNodeAs<MemberExpr>("MemberExpr")) {
+ Diag << ME->getMemberNameInfo().getName();
+ } else
Diag << "unknown method";
Diag << Hint;
} else {
diff --git a/clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.h b/clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.h
index 79b0d39..1b12fec 100644
--- a/clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.h
+++ b/clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.h
@@ -23,6 +23,9 @@ class ConvertMemberFunctionsToStatic : public ClangTidyCheck {
public:
ConvertMemberFunctionsToStatic(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
diff --git a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h
index e9e7c94..6e746d8 100644
--- a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h
@@ -22,6 +22,9 @@ class DeleteNullPointerCheck : public ClangTidyCheck {
public:
DeleteNullPointerCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
std::optional<TraversalKind> getCheckTraversalKind() const override {
diff --git a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp
index b4a157c..9eef5c4 100644
--- a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp
@@ -122,15 +122,15 @@ AST_MATCHER(EnumDecl, hasSequentialInitialValues) {
return !AllEnumeratorsArePowersOfTwo;
}
-std::string getName(const EnumDecl *Decl) {
+} // namespace
+
+static std::string getName(const EnumDecl *Decl) {
if (!Decl->getDeclName())
return "<unnamed>";
return Decl->getQualifiedNameAsString();
}
-} // namespace
-
EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
diff --git a/clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp b/clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
index e1fb42b..2f59aaa 100644
--- a/clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
@@ -144,6 +144,8 @@ struct CognitiveComplexity final {
void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
};
+} // namespace
+
// All the possible messages that can be output. The choice of the message
// to use is based of the combination of the CognitiveComplexity::Criteria.
// It would be nice to have it in CognitiveComplexity struct, but then it is
@@ -163,23 +165,27 @@ static const std::array<const StringRef, 4> Msgs = {{
}};
// Criteria is a bitset, thus a few helpers are needed.
-CognitiveComplexity::Criteria operator|(CognitiveComplexity::Criteria LHS,
- CognitiveComplexity::Criteria RHS) {
+static CognitiveComplexity::Criteria
+operator|(CognitiveComplexity::Criteria LHS,
+ CognitiveComplexity::Criteria RHS) {
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) |
llvm::to_underlying(RHS));
}
-CognitiveComplexity::Criteria operator&(CognitiveComplexity::Criteria LHS,
- CognitiveComplexity::Criteria RHS) {
+static CognitiveComplexity::Criteria
+operator&(CognitiveComplexity::Criteria LHS,
+ CognitiveComplexity::Criteria RHS) {
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) &
llvm::to_underlying(RHS));
}
-CognitiveComplexity::Criteria &operator|=(CognitiveComplexity::Criteria &LHS,
- CognitiveComplexity::Criteria RHS) {
+static CognitiveComplexity::Criteria &
+operator|=(CognitiveComplexity::Criteria &LHS,
+ CognitiveComplexity::Criteria RHS) {
LHS = operator|(LHS, RHS);
return LHS;
}
-CognitiveComplexity::Criteria &operator&=(CognitiveComplexity::Criteria &LHS,
- CognitiveComplexity::Criteria RHS) {
+static CognitiveComplexity::Criteria &
+operator&=(CognitiveComplexity::Criteria &LHS,
+ CognitiveComplexity::Criteria RHS) {
LHS = operator&(LHS, RHS);
return LHS;
}
@@ -199,6 +205,8 @@ void CognitiveComplexity::account(SourceLocation Loc, unsigned short Nesting,
Total += Increase;
}
+namespace {
+
class FunctionASTVisitor final
: public RecursiveASTVisitor<FunctionASTVisitor> {
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
index fab2365..3df4a03 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -953,7 +953,7 @@ std::string IdentifierNamingCheck::fixupWithCase(
break;
case IdentifierNamingCheck::CT_LowerCase:
- for (auto const &Word : Words) {
+ for (const auto &Word : Words) {
if (&Word != &Words.front())
Fixup += "_";
Fixup += Word.lower();
@@ -961,7 +961,7 @@ std::string IdentifierNamingCheck::fixupWithCase(
break;
case IdentifierNamingCheck::CT_UpperCase:
- for (auto const &Word : Words) {
+ for (const auto &Word : Words) {
if (&Word != &Words.front())
Fixup += "_";
Fixup += Word.upper();
@@ -969,14 +969,14 @@ std::string IdentifierNamingCheck::fixupWithCase(
break;
case IdentifierNamingCheck::CT_CamelCase:
- for (auto const &Word : Words) {
+ for (const auto &Word : Words) {
Fixup += toupper(Word.front());
Fixup += Word.substr(1).lower();
}
break;
case IdentifierNamingCheck::CT_CamelBack:
- for (auto const &Word : Words) {
+ for (const auto &Word : Words) {
if (&Word == &Words.front()) {
Fixup += Word.lower();
} else {
@@ -987,7 +987,7 @@ std::string IdentifierNamingCheck::fixupWithCase(
break;
case IdentifierNamingCheck::CT_CamelSnakeCase:
- for (auto const &Word : Words) {
+ for (const auto &Word : Words) {
if (&Word != &Words.front())
Fixup += "_";
Fixup += toupper(Word.front());
@@ -996,7 +996,7 @@ std::string IdentifierNamingCheck::fixupWithCase(
break;
case IdentifierNamingCheck::CT_CamelSnakeBack:
- for (auto const &Word : Words) {
+ for (const auto &Word : Words) {
if (&Word != &Words.front()) {
Fixup += "_";
Fixup += toupper(Word.front());
@@ -1008,7 +1008,7 @@ std::string IdentifierNamingCheck::fixupWithCase(
break;
case IdentifierNamingCheck::CT_LeadingUpperSnakeCase:
- for (auto const &Word : Words) {
+ for (const auto &Word : Words) {
if (&Word != &Words.front()) {
Fixup += "_";
Fixup += Word.lower();
diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
index 5f19706..6b10e6b 100644
--- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -41,9 +41,11 @@ AST_MATCHER(Stmt, isNULLMacroExpansion) {
return isNULLMacroExpansion(&Node, Finder->getASTContext());
}
-StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
- QualType Type,
- ASTContext &Context) {
+} // namespace
+
+static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
+ QualType Type,
+ ASTContext &Context) {
switch (CastExprKind) {
case CK_IntegralToBoolean:
return Type->isUnsignedIntegerType() ? "0u" : "0";
@@ -62,15 +64,15 @@ StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
}
}
-bool isUnaryLogicalNotOperator(const Stmt *Statement) {
+static bool isUnaryLogicalNotOperator(const Stmt *Statement) {
const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
}
-void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
- const ImplicitCastExpr *Cast, const Stmt *Parent,
- ASTContext &Context,
- bool UseUpperCaseLiteralSuffix) {
+static void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
+ const ImplicitCastExpr *Cast,
+ const Stmt *Parent, ASTContext &Context,
+ bool UseUpperCaseLiteralSuffix) {
// In case of expressions like (! integer), we should remove the redundant not
// operator and use inverted comparison (integer == 0).
bool InvertComparison =
@@ -133,8 +135,8 @@ void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
}
-StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
- ASTContext &Context) {
+static StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
+ ASTContext &Context) {
if (isNULLMacroExpansion(Expression, Context)) {
return "false";
}
@@ -161,7 +163,7 @@ StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
return {};
}
-bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
+static bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc);
StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(),
@@ -173,9 +175,10 @@ bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
return !AllowedCharacters.contains(SpaceBeforeStmtStr.back());
}
-void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
- const ImplicitCastExpr *Cast,
- ASTContext &Context, StringRef OtherType) {
+static void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
+ const ImplicitCastExpr *Cast,
+ ASTContext &Context,
+ StringRef OtherType) {
if (!Context.getLangOpts().CPlusPlus) {
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
(Twine("(") + OtherType + ")").str());
@@ -200,8 +203,9 @@ void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
}
}
-StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
- QualType DestType, ASTContext &Context) {
+static StringRef
+getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
+ QualType DestType, ASTContext &Context) {
// Prior to C++11, false literal could be implicitly converted to pointer.
if (!Context.getLangOpts().CPlusPlus11 &&
(DestType->isPointerType() || DestType->isMemberPointerType()) &&
@@ -222,8 +226,8 @@ StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
return BoolLiteral->getValue() ? "1" : "0";
}
-bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
- ASTContext &Context) {
+static bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
+ ASTContext &Context) {
std::queue<const Stmt *> Q;
Q.push(Cast);
@@ -251,8 +255,6 @@ bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
return false;
}
-} // anonymous namespace
-
ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
index 561f067..44a784b 100644
--- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
@@ -28,8 +28,11 @@ AST_MATCHER_P(QualType, hasUnqualifiedType,
enum class Qualifier { Const, Volatile, Restrict };
-std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
- const MatchFinder::MatchResult &Result) {
+} // namespace
+
+static std::optional<Token>
+findQualToken(const VarDecl *Decl, Qualifier Qual,
+ const MatchFinder::MatchResult &Result) {
// Since either of the locs can be in a macro, use `makeFileCharRange` to be
// sure that we have a consistent `CharSourceRange`, located entirely in the
// source file.
@@ -58,7 +61,7 @@ std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
*Result.SourceManager);
}
-std::optional<SourceRange>
+static std::optional<SourceRange>
getTypeSpecifierLocation(const VarDecl *Var,
const MatchFinder::MatchResult &Result) {
SourceRange TypeSpecifier(
@@ -73,8 +76,8 @@ getTypeSpecifierLocation(const VarDecl *Var,
return TypeSpecifier;
}
-std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
- const Token &ConstToken) {
+static std::optional<SourceRange>
+mergeReplacementRange(SourceRange &TypeSpecifier, const Token &ConstToken) {
if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
TypeSpecifier.setBegin(ConstToken.getLocation());
return std::nullopt;
@@ -86,21 +89,19 @@ std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
}
-bool isPointerConst(QualType QType) {
+static bool isPointerConst(QualType QType) {
QualType Pointee = QType->getPointeeType();
assert(!Pointee.isNull() && "can't have a null Pointee");
return Pointee.isConstQualified();
}
-bool isAutoPointerConst(QualType QType) {
+static bool isAutoPointerConst(QualType QType) {
QualType Pointee =
cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar();
assert(!Pointee.isNull() && "can't have a null Pointee");
return Pointee.isConstQualified();
}
-} // namespace
-
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
index 70016a3..d93077c 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
@@ -14,19 +14,18 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
-namespace {
+static const char *const RedundantReturnDiag =
+ "redundant return statement at the end "
+ "of a function with a void return type";
+static const char *const RedundantContinueDiag =
+ "redundant continue statement at the "
+ "end of loop statement";
-const char *const RedundantReturnDiag = "redundant return statement at the end "
- "of a function with a void return type";
-const char *const RedundantContinueDiag = "redundant continue statement at the "
- "end of loop statement";
-
-bool isLocationInMacroExpansion(const SourceManager &SM, SourceLocation Loc) {
+static bool isLocationInMacroExpansion(const SourceManager &SM,
+ SourceLocation Loc) {
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
}
-} // namespace
-
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
functionDecl(isDefinition(), returns(voidType()),
diff --git a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
index fffb136..a7b3c4a 100644
--- a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
@@ -19,19 +19,25 @@ namespace {
AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); }
} // namespace
-static unsigned getNameSpecifierNestingLevel(const QualType &QType) {
- if (const auto *ElType = QType->getAs<ElaboratedType>()) {
- if (const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier()) {
- unsigned NameSpecifierNestingLevel = 1;
- do {
- NameSpecifierNestingLevel++;
- NestedSpecifiers = NestedSpecifiers->getPrefix();
- } while (NestedSpecifiers);
-
+static unsigned getNameSpecifierNestingLevel(QualType QType) {
+ unsigned NameSpecifierNestingLevel = 1;
+ for (NestedNameSpecifier Qualifier = QType->getPrefix(); /**/;
+ ++NameSpecifierNestingLevel) {
+ switch (Qualifier.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
return NameSpecifierNestingLevel;
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ return NameSpecifierNestingLevel + 1;
+ case NestedNameSpecifier::Kind::Namespace:
+ Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix;
+ continue;
+ case NestedNameSpecifier::Kind::Type:
+ Qualifier = Qualifier.getAsType()->getPrefix();
+ continue;
}
+ llvm_unreachable("unhandled nested name specifier kind");
}
- return 0;
}
void StaticAccessedThroughInstanceCheck::storeOptions(
diff --git a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h
index 4044f13..9869855 100644
--- a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h
@@ -24,6 +24,9 @@ public:
: ClangTidyCheck(Name, Context),
NameSpecifierNestingThreshold(
Options.get("NameSpecifierNestingThreshold", 3U)) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
index 5a04029..a80637d 100644
--- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
@@ -413,10 +413,11 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
// Arithmetic types are interconvertible, except scoped enums.
if (ParamType->isArithmeticType() && ArgType->isArithmeticType()) {
- if ((ParamType->isEnumeralType() &&
- ParamType->castAs<EnumType>()->getDecl()->isScoped()) ||
+ if ((ParamType->isEnumeralType() && ParamType->castAsCanonical<EnumType>()
+ ->getOriginalDecl()
+ ->isScoped()) ||
(ArgType->isEnumeralType() &&
- ArgType->castAs<EnumType>()->getDecl()->isScoped()))
+ ArgType->castAsCanonical<EnumType>()->getOriginalDecl()->isScoped()))
return false;
return true;
diff --git a/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h b/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h
index 4dfcf36..2768955 100644
--- a/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h
@@ -21,6 +21,9 @@ namespace clang::tidy::readability {
class UniqueptrDeleteReleaseCheck : public ClangTidyCheck {
public:
UniqueptrDeleteReleaseCheck(StringRef Name, ClangTidyContext *Context);
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
diff --git a/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp b/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp
index 678aa8d..4ec2a63 100644
--- a/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp
@@ -25,14 +25,12 @@ struct IntegerLiteralCheck {
static constexpr llvm::StringLiteral Name = llvm::StringLiteral("integer");
// What should be skipped before looking for the Suffixes? (Nothing here.)
static constexpr llvm::StringLiteral SkipFirst = llvm::StringLiteral("");
- // Suffix can only consist of 'u' and 'l' chars, and can be a complex number
- // ('i', 'j'). In MS compatibility mode, suffixes like i32 are supported.
+ // Suffix can only consist of 'u', 'l', and 'z' chars, can be a bit-precise
+ // integer (wb), and can be a complex number ('i', 'j'). In MS compatibility
+ // mode, suffixes like i32 are supported.
static constexpr llvm::StringLiteral Suffixes =
- llvm::StringLiteral("uUlLiIjJ");
+ llvm::StringLiteral("uUlLzZwWbBiIjJ");
};
-constexpr llvm::StringLiteral IntegerLiteralCheck::Name;
-constexpr llvm::StringLiteral IntegerLiteralCheck::SkipFirst;
-constexpr llvm::StringLiteral IntegerLiteralCheck::Suffixes;
struct FloatingLiteralCheck {
using type = clang::FloatingLiteral;
@@ -45,14 +43,11 @@ struct FloatingLiteralCheck {
// Since the exponent ('p'/'P') is mandatory for hexadecimal floating-point
// literals, we first skip everything before the exponent.
static constexpr llvm::StringLiteral SkipFirst = llvm::StringLiteral("pP");
- // Suffix can only consist of 'f', 'l', "f16", 'h', 'q' chars,
- // and can be a complex number ('i', 'j').
+ // Suffix can only consist of 'f', 'l', "f16", "bf16", "df", "dd", "dl",
+ // 'h', 'q' chars, and can be a complex number ('i', 'j').
static constexpr llvm::StringLiteral Suffixes =
- llvm::StringLiteral("fFlLhHqQiIjJ");
+ llvm::StringLiteral("fFlLbBdDhHqQiIjJ");
};
-constexpr llvm::StringLiteral FloatingLiteralCheck::Name;
-constexpr llvm::StringLiteral FloatingLiteralCheck::SkipFirst;
-constexpr llvm::StringLiteral FloatingLiteralCheck::Suffixes;
struct NewSuffix {
SourceRange LiteralLocation;
diff --git a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
index 6f6b8a8..718467ed 100644
--- a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp
@@ -67,11 +67,7 @@ static QualType getNonTemplateAlias(QualType QT) {
if (!TT->getDecl()->getDescribedTemplate() &&
!TT->getDecl()->getDeclContext()->isDependentContext())
return QT;
- QT = TT->getDecl()->getUnderlyingType();
- }
- // cast to elaborated type
- else if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(QT)) {
- QT = ET->getNamedType();
+ QT = TT->desugar();
} else {
break;
}
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index 97dfd0f..bef3b93 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -162,14 +162,19 @@ in .clang-tidy file, if any.
cl::init(false), cl::cat(ClangTidyCategory));
static cl::opt<std::string> LineFilter("line-filter", desc(R"(
-List of files with line ranges to filter the
-warnings. Can be used together with
--header-filter. The format of the list is a
-JSON array of objects:
+List of files and line ranges to output diagnostics from.
+The range is inclusive on both ends. Can be used together
+with -header-filter. The format of the list is a JSON
+array of objects. For example:
+
[
{"name":"file1.cpp","lines":[[1,3],[5,7]]},
{"name":"file2.h"}
]
+
+This will output diagnostics from 'file1.cpp' only for
+the line ranges [1,3] and [5,7], as well as all from the
+entire 'file2.h'.
)"),
cl::init(""),
cl::cat(ClangTidyCategory));
@@ -712,7 +717,7 @@ int clangTidyMain(int argc, const char **argv) {
EnableModuleHeadersParsing);
std::vector<ClangTidyError> Errors =
runClangTidy(Context, OptionsParser->getCompilations(), PathList, BaseFS,
- FixNotes, EnableCheckProfile, ProfilePrefix);
+ FixNotes, EnableCheckProfile, ProfilePrefix, Quiet);
bool FoundErrors = llvm::any_of(Errors, [](const ClangTidyError &E) {
return E.DiagLevel == ClangTidyError::Error;
});
diff --git a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
index 7cd21af..d7899e0 100755
--- a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
+++ b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
@@ -28,6 +28,7 @@ import glob
import json
import multiprocessing
import os
+import queue
import re
import shutil
import subprocess
@@ -42,13 +43,6 @@ try:
except ImportError:
yaml = None
-is_py2 = sys.version[0] == "2"
-
-if is_py2:
- import Queue as queue
-else:
- import queue as queue
-
def run_tidy(task_queue, lock, timeout, failed_files):
watchdog = None
diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
index 80f1766..670e0a2 100755
--- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
+++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
@@ -483,7 +483,7 @@ async def main() -> None:
parser.add_argument(
"-line-filter",
default=None,
- help="List of files with line ranges to filter the warnings.",
+ help="List of files and line ranges to output diagnostics from.",
)
if yaml:
parser.add_argument(
diff --git a/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp
index 6914ec2..d43716e 100644
--- a/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp
+++ b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp
@@ -13,6 +13,7 @@
#include "DesignatedInitializers.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/ScopeExit.h"
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
index 0637d0e..4693c65 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
@@ -9,6 +9,7 @@
#include "ExceptionSpecAnalyzer.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
namespace clang::tidy::utils {
@@ -66,9 +67,7 @@ ExceptionSpecAnalyzer::analyzeBase(const CXXBaseSpecifier &Base,
if (!RecType)
return State::Unknown;
- const auto *BaseClass = cast<CXXRecordDecl>(RecType->getDecl());
-
- return analyzeRecord(BaseClass, Kind);
+ return analyzeRecord(RecType->getAsCXXRecordDecl(), Kind);
}
ExceptionSpecAnalyzer::State
diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
index e1c1bee..0d0834d 100644
--- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
+++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
@@ -460,9 +460,9 @@ bool FormatStringConverter::emitIntegerArgument(
// be passed as its underlying type. However, printf will have forced
// the signedness based on the format string, so we need to do the
// same.
- if (const auto *ET = ArgType->getAs<EnumType>()) {
+ if (const auto *ED = ArgType->getAsEnumDecl()) {
if (const std::optional<std::string> MaybeCastType =
- castTypeForArgument(ArgKind, ET->getDecl()->getIntegerType()))
+ castTypeForArgument(ArgKind, ED->getIntegerType()))
ArgFixes.emplace_back(
ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str());
else
diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.cpp b/clang-tools-extra/clang-tidy/utils/Matchers.cpp
index 4974a9c..bd7b03e 100644
--- a/clang-tools-extra/clang-tidy/utils/Matchers.cpp
+++ b/clang-tools-extra/clang-tidy/utils/Matchers.cpp
@@ -34,7 +34,7 @@ bool MatchesAnyListedTypeNameMatcher::matches(
PrintingPolicy PrintingPolicyWithSuppressedTag(
Finder->getASTContext().getLangOpts());
PrintingPolicyWithSuppressedTag.PrintAsCanonical = CanonicalTypes;
- PrintingPolicyWithSuppressedTag.SuppressElaboration = true;
+ PrintingPolicyWithSuppressedTag.FullyQualifiedName = true;
PrintingPolicyWithSuppressedTag.SuppressScope = false;
PrintingPolicyWithSuppressedTag.SuppressTagKeyword = true;
PrintingPolicyWithSuppressedTag.SuppressUnwrittenScope = true;
diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
index eaa04fe..90539ea 100644
--- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
@@ -194,6 +194,8 @@ public:
return;
if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
return;
+ if (SM.isInSystemHeader(MacroNameTok.getLocation()))
+ return;
Check->checkMacro(MacroNameTok, Info, SM);
}
@@ -281,9 +283,10 @@ public:
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) {
- if (const NestedNameSpecifier *Spec = Loc.getNestedNameSpecifier()) {
+ if (NestedNameSpecifier Spec = Loc.getNestedNameSpecifier();
+ Spec.getKind() == NestedNameSpecifier::Kind::Namespace) {
if (const auto *Decl =
- dyn_cast_if_present<NamespaceDecl>(Spec->getAsNamespace()))
+ dyn_cast<NamespaceDecl>(Spec.getAsNamespaceAndPrefix().Namespace))
Check->addUsage(Decl, Loc.getLocalSourceRange(), SM);
}
@@ -323,48 +326,34 @@ public:
}
bool VisitTypedefTypeLoc(const TypedefTypeLoc &Loc) {
- Check->addUsage(Loc.getTypedefNameDecl(), Loc.getSourceRange(), SM);
+ Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
return true;
}
bool VisitTagTypeLoc(const TagTypeLoc &Loc) {
- Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
- return true;
- }
-
- bool VisitInjectedClassNameTypeLoc(const InjectedClassNameTypeLoc &Loc) {
- Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
+ Check->addUsage(Loc.getOriginalDecl(), Loc.getNameLoc(), SM);
return true;
}
bool VisitUnresolvedUsingTypeLoc(const UnresolvedUsingTypeLoc &Loc) {
- Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
+ Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
return true;
}
bool VisitTemplateTypeParmTypeLoc(const TemplateTypeParmTypeLoc &Loc) {
- Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
+ Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
return true;
}
bool
VisitTemplateSpecializationTypeLoc(const TemplateSpecializationTypeLoc &Loc) {
const TemplateDecl *Decl =
- Loc.getTypePtr()->getTemplateName().getAsTemplateDecl();
+ Loc.getTypePtr()->getTemplateName().getAsTemplateDecl(
+ /*IgnoreDeduced=*/true);
- SourceRange Range(Loc.getTemplateNameLoc(), Loc.getTemplateNameLoc());
- if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
+ if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl))
if (const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
- Check->addUsage(TemplDecl, Range, SM);
- }
-
- return true;
- }
-
- bool VisitDependentTemplateSpecializationTypeLoc(
- const DependentTemplateSpecializationTypeLoc &Loc) {
- if (const TagDecl *Decl = Loc.getTypePtr()->getAsTagDecl())
- Check->addUsage(Decl, Loc.getSourceRange(), SM);
+ Check->addUsage(TemplDecl, Loc.getTemplateNameLoc(), SM);
return true;
}
diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
index 44db0c2..f944306 100644
--- a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
+++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
@@ -13,16 +13,14 @@
namespace clang::tidy::utils::type_traits {
-namespace {
-
-bool classHasTrivialCopyAndDestroy(QualType Type) {
+static bool classHasTrivialCopyAndDestroy(QualType Type) {
auto *Record = Type->getAsCXXRecordDecl();
return Record && Record->hasDefinition() &&
!Record->hasNonTrivialCopyConstructor() &&
!Record->hasNonTrivialDestructor();
}
-bool hasDeletedCopyConstructor(QualType Type) {
+static bool hasDeletedCopyConstructor(QualType Type) {
auto *Record = Type->getAsCXXRecordDecl();
if (!Record || !Record->hasDefinition())
return false;
@@ -33,8 +31,6 @@ bool hasDeletedCopyConstructor(QualType Type) {
return false;
}
-} // namespace
-
std::optional<bool> isExpensiveToCopy(QualType Type,
const ASTContext &Context) {
if (Type->isDependentType() || Type->isIncompleteType())
@@ -123,8 +119,8 @@ bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) {
if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
return true;
- if (const auto *RT = CanonicalType->getAs<RecordType>()) {
- return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context);
+ if (const auto *RD = CanonicalType->getAsRecordDecl()) {
+ return recordIsTriviallyDefaultConstructible(*RD, Context);
}
// No other types can match.
diff --git a/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h b/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h
index e1f1f06..b2d5ab6 100644
--- a/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h
+++ b/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h
@@ -24,6 +24,9 @@ public:
TemporaryObjectsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
Names(utils::options::parseStringList(Options.get("Names", ""))) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index f2631e5..2f46ecc 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -102,54 +102,78 @@ getUsingNamespaceDirectives(const DeclContext *DestContext,
// ancestor is redundant, therefore we stop at lowest common ancestor.
// In addition to that stops early whenever IsVisible returns true. This can be
// used to implement support for "using namespace" decls.
-std::string
-getQualification(ASTContext &Context, const DeclContext *DestContext,
- const DeclContext *SourceContext,
- llvm::function_ref<bool(NestedNameSpecifier *)> IsVisible) {
- std::vector<const NestedNameSpecifier *> Parents;
- bool ReachedNS = false;
+std::string getQualification(ASTContext &Context,
+ const DeclContext *DestContext,
+ const DeclContext *SourceContext,
+ llvm::function_ref<bool(const Decl *)> IsVisible) {
+ std::vector<const Decl *> Parents;
+ [[maybe_unused]] bool ReachedNS = false;
for (const DeclContext *CurContext = SourceContext; CurContext;
CurContext = CurContext->getLookupParent()) {
// Stop once we reach a common ancestor.
if (CurContext->Encloses(DestContext))
break;
- NestedNameSpecifier *NNS = nullptr;
+ const Decl *CurD;
if (auto *TD = llvm::dyn_cast<TagDecl>(CurContext)) {
// There can't be any more tag parents after hitting a namespace.
assert(!ReachedNS);
- (void)ReachedNS;
- NNS = NestedNameSpecifier::Create(Context, nullptr, TD->getTypeForDecl());
+ CurD = TD;
} else if (auto *NSD = llvm::dyn_cast<NamespaceDecl>(CurContext)) {
ReachedNS = true;
- NNS = NestedNameSpecifier::Create(Context, nullptr, NSD);
// Anonymous and inline namespace names are not spelled while qualifying
// a name, so skip those.
if (NSD->isAnonymousNamespace() || NSD->isInlineNamespace())
continue;
+ CurD = NSD;
} else {
// Other types of contexts cannot be spelled in code, just skip over
// them.
continue;
}
// Stop if this namespace is already visible at DestContext.
- if (IsVisible(NNS))
+ if (IsVisible(CurD))
break;
- Parents.push_back(NNS);
+ Parents.push_back(CurD);
+ }
+
+ // Go over the declarations in reverse order, since we stored inner-most
+ // parent first.
+ NestedNameSpecifier Qualifier = std::nullopt;
+ bool IsFirst = true;
+ for (const auto *CurD : llvm::reverse(Parents)) {
+ if (auto *TD = llvm::dyn_cast<TagDecl>(CurD)) {
+ QualType T;
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(TD);
+ ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) {
+ ArrayRef<TemplateArgument> Args;
+ if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ Args = SD->getTemplateArgs().asArray();
+ else
+ Args = CTD->getTemplateParameters()->getInjectedTemplateArgs(Context);
+ T = Context.getTemplateSpecializationType(
+ ElaboratedTypeKeyword::None,
+ Context.getQualifiedTemplateName(
+ Qualifier, /*TemplateKeyword=*/!IsFirst, TemplateName(CTD)),
+ Args, /*CanonicalArgs=*/{}, Context.getCanonicalTagType(RD));
+ } else {
+ T = Context.getTagType(ElaboratedTypeKeyword::None, Qualifier, TD,
+ /*OwnsTag=*/false);
+ }
+ Qualifier = NestedNameSpecifier(T.getTypePtr());
+ } else {
+ Qualifier =
+ NestedNameSpecifier(Context, cast<NamespaceDecl>(CurD), Qualifier);
+ }
+ IsFirst = false;
}
+ if (!Qualifier)
+ return "";
- // Go over name-specifiers in reverse order to create necessary qualification,
- // since we stored inner-most parent first.
std::string Result;
llvm::raw_string_ostream OS(Result);
- for (const auto *Parent : llvm::reverse(Parents)) {
- if (Parent != *Parents.rbegin() && Parent->isDependent() &&
- Parent->getAsRecordDecl() &&
- Parent->getAsRecordDecl()->getDescribedClassTemplate())
- OS << "template ";
- Parent->print(OS, Context.getPrintingPolicy());
- }
+ Qualifier.print(OS, Context.getPrintingPolicy());
return OS.str();
}
@@ -187,6 +211,7 @@ std::string printQualifiedName(const NamedDecl &ND) {
// include them, but at query time it's hard to find all the inline
// namespaces to query: the preamble doesn't have a dedicated list.
Policy.SuppressUnwrittenScope = true;
+ Policy.SuppressScope = true;
// (unnamed struct), not (unnamed struct at /path/to/foo.cc:42:1).
// In clangd, context is usually available and paths are mostly noise.
Policy.AnonymousTagLocations = false;
@@ -213,8 +238,7 @@ std::string printUsingNamespaceName(const ASTContext &Ctx,
std::string Name;
llvm::raw_string_ostream Out(Name);
- if (auto *Qual = D.getQualifier())
- Qual->print(Out, PP);
+ D.getQualifier().print(Out, PP);
D.getNominatedNamespaceAsWritten()->printName(Out);
return Out.str();
}
@@ -229,8 +253,7 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
// Handle 'using namespace'. They all have the same name - <using-directive>.
if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
Out << "using namespace ";
- if (auto *Qual = UD->getQualifier())
- Qual->print(Out, PP);
+ UD->getQualifier().print(Out, PP);
UD->getNominatedNamespaceAsWritten()->printName(Out);
return Out.str();
}
@@ -250,8 +273,7 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
}
// Print nested name qualifier if it was written in the source code.
- if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier())
- Qualifier->print(Out, PP);
+ getQualifierLoc(ND).getNestedNameSpecifier().print(Out, PP);
// Print the name itself.
ND.getDeclName().print(Out, PP);
// Print template arguments.
@@ -391,12 +413,13 @@ preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts,
}
std::string printType(const QualType QT, const DeclContext &CurContext,
- const llvm::StringRef Placeholder) {
+ const llvm::StringRef Placeholder, bool FullyQualify) {
std::string Result;
llvm::raw_string_ostream OS(Result);
PrintingPolicy PP(CurContext.getParentASTContext().getPrintingPolicy());
PP.SuppressTagKeyword = true;
PP.SuppressUnwrittenScope = true;
+ PP.FullyQualifiedName = FullyQualify;
class PrintCB : public PrintingCallbacks {
public:
@@ -439,6 +462,7 @@ QualType declaredType(const TypeDecl *D) {
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
if (const auto *Args = CTSD->getTemplateArgsAsWritten())
return Context.getTemplateSpecializationType(
+ ElaboratedTypeKeyword::None,
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(),
/*CanonicalArgs=*/{});
return Context.getTypeDeclType(D);
@@ -664,13 +688,10 @@ std::string getQualification(ASTContext &Context,
auto VisibleNamespaceDecls =
getUsingNamespaceDirectives(DestContext, InsertionPoint);
return getQualification(
- Context, DestContext, ND->getDeclContext(),
- [&](NestedNameSpecifier *NNS) {
- const NamespaceDecl *NS =
- dyn_cast_if_present<NamespaceDecl>(NNS->getAsNamespace());
- if (!NS)
+ Context, DestContext, ND->getDeclContext(), [&](const Decl *D) {
+ if (D->getKind() != Decl::Namespace)
return false;
- NS = NS->getCanonicalDecl();
+ const auto *NS = cast<NamespaceDecl>(D)->getCanonicalDecl();
return llvm::any_of(VisibleNamespaceDecls,
[NS](const NamespaceDecl *NSD) {
return NSD->getCanonicalDecl() == NS;
@@ -687,12 +708,11 @@ std::string getQualification(ASTContext &Context,
(void)NS;
}
return getQualification(
- Context, DestContext, ND->getDeclContext(),
- [&](NestedNameSpecifier *NNS) {
+ Context, DestContext, ND->getDeclContext(), [&](const Decl *D) {
return llvm::any_of(VisibleNamespaces, [&](llvm::StringRef Namespace) {
std::string NS;
llvm::raw_string_ostream OS(NS);
- NNS->print(OS, Context.getPrintingPolicy());
+ D->print(OS, Context.getPrintingPolicy());
return OS.str() == Namespace;
});
});
@@ -965,7 +985,7 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) {
// Recurse on pack parameters
size_t Depth = 0;
const FunctionDecl *CurrentFunction = D;
- llvm::SmallSet<const FunctionTemplateDecl *, 4> SeenTemplates;
+ llvm::SmallPtrSet<const FunctionTemplateDecl *, 4> SeenTemplates;
if (const auto *Template = D->getPrimaryTemplate()) {
SeenTemplates.insert(Template);
}
diff --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h
index fb0722d..1538d12 100644
--- a/clang-tools-extra/clangd/AST.h
+++ b/clang-tools-extra/clangd/AST.h
@@ -135,7 +135,8 @@ preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts,
/// Returns a QualType as string. The result doesn't contain unwritten scopes
/// like anonymous/inline namespace.
std::string printType(const QualType QT, const DeclContext &CurContext,
- llvm::StringRef Placeholder = "");
+ llvm::StringRef Placeholder = "",
+ bool FullyQualify = false);
/// Indicates if \p D is a template instantiation implicitly generated by the
/// compiler, e.g.
diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt
index a1e9da4..fb3f053 100644
--- a/clang-tools-extra/clangd/CMakeLists.txt
+++ b/clang-tools-extra/clangd/CMakeLists.txt
@@ -6,7 +6,7 @@ add_subdirectory(support)
# Configure the Features.inc file.
if (NOT DEFINED CLANGD_BUILD_XPC)
- if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
set(CLANGD_BUILD_XPC_DEFAULT ON)
else ()
set(CLANGD_BUILD_XPC_DEFAULT OFF)
@@ -108,6 +108,7 @@ add_clang_library(clangDaemon STATIC
SemanticHighlighting.cpp
SemanticSelection.cpp
SourceCode.cpp
+ SymbolDocumentation.cpp
SystemIncludeExtractor.cpp
TidyProvider.cpp
TUScheduler.cpp
@@ -192,7 +193,7 @@ if(CLANGD_TIDY_CHECKS)
endif()
add_subdirectory(refactor/tweaks)
-if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
# FIXME: Make fuzzer not use linux-specific APIs, build it everywhere.
add_subdirectory(fuzzer)
endif()
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 9c17b4c..c6deed3 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -97,6 +97,9 @@ toCompletionItemKind(index::SymbolKind Kind,
const llvm::StringRef *Signature = nullptr) {
using SK = index::SymbolKind;
switch (Kind) {
+ // FIXME: for backwards compatibility, the include directive kind is treated
+ // the same as Unknown
+ case SK::IncludeDirective:
case SK::Unknown:
return CompletionItemKind::Missing;
case SK::Module:
@@ -1466,19 +1469,15 @@ bool allowIndex(CodeCompletionContext &CC) {
auto Scope = CC.getCXXScopeSpecifier();
if (!Scope)
return true;
- NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
- if (!NameSpec)
- return true;
// We only query the index when qualifier is a namespace.
// If it's a class, we rely solely on sema completions.
- switch (NameSpec->getKind()) {
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Namespace:
+ switch ((*Scope)->getScopeRep().getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::Namespace:
return true;
- case NestedNameSpecifier::Super:
- case NestedNameSpecifier::TypeSpec:
- // Unresolved inside a template.
- case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ case NestedNameSpecifier::Kind::Type:
return false;
}
llvm_unreachable("invalid NestedNameSpecifier kind");
@@ -2434,6 +2433,9 @@ CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const {
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const CodeCompletion &C) {
+ OS << "Signature: " << "\"" << C.Signature << "\", "
+ << "SnippetSuffix: " << "\"" << C.SnippetSuffix << "\""
+ << ", Rendered:";
// For now just lean on CompletionItem.
return OS << C.render(CodeCompleteOptions());
}
diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.cpp b/clang-tools-extra/clangd/CodeCompletionStrings.cpp
index 9b4442b..9c4241b 100644
--- a/clang-tools-extra/clangd/CodeCompletionStrings.cpp
+++ b/clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -7,13 +7,18 @@
//===----------------------------------------------------------------------===//
#include "CodeCompletionStrings.h"
+#include "Config.h"
+#include "SymbolDocumentation.h"
#include "clang-c/Index.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/RawCommentList.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
#include <limits>
#include <utility>
@@ -100,16 +105,55 @@ std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl) {
// the comments for namespaces.
return "";
}
- const RawComment *RC = getCompletionComment(Ctx, &Decl);
- if (!RC)
- return "";
- // Sanity check that the comment does not come from the PCH. We choose to not
- // write them into PCH, because they are racy and slow to load.
- assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getBeginLoc()));
- std::string Doc =
- RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
- if (!looksLikeDocComment(Doc))
- return "";
+
+ const RawComment *RC = nullptr;
+ const Config &Cfg = Config::current();
+
+ std::string Doc;
+
+ if (Cfg.Documentation.CommentFormat == Config::CommentFormatPolicy::Doxygen &&
+ isa<ParmVarDecl, TemplateTypeParmDecl>(Decl)) {
+ // Parameters are documented in their declaration context (function or
+ // template function).
+ const NamedDecl *ND = dyn_cast<NamedDecl>(Decl.getDeclContext());
+ if (!ND)
+ return "";
+
+ RC = getCompletionComment(Ctx, ND);
+ if (!RC)
+ return "";
+
+ // Sanity check that the comment does not come from the PCH. We choose to
+ // not write them into PCH, because they are racy and slow to load.
+ assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getBeginLoc()));
+
+ comments::FullComment *FC = RC->parse(Ctx, /*PP=*/nullptr, ND);
+ if (!FC)
+ return "";
+
+ SymbolDocCommentVisitor V(FC, Ctx.getLangOpts().CommentOpts);
+ std::string RawDoc;
+ llvm::raw_string_ostream OS(RawDoc);
+
+ if (auto *PVD = dyn_cast<ParmVarDecl>(&Decl))
+ V.parameterDocToString(PVD->getName(), OS);
+ else
+ V.templateTypeParmDocToString(
+ cast<TemplateTypeParmDecl>(&Decl)->getName(), OS);
+
+ Doc = StringRef(RawDoc).trim().str();
+ } else {
+ RC = getCompletionComment(Ctx, &Decl);
+ if (!RC)
+ return "";
+ // Sanity check that the comment does not come from the PCH. We choose to
+ // not write them into PCH, because they are racy and slow to load.
+ assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getBeginLoc()));
+ Doc = RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
+ if (!looksLikeDocComment(Doc))
+ return "";
+ }
+
// Clang requires source to be UTF-8, but doesn't enforce this in comments.
if (!llvm::json::isUTF8(Doc))
Doc = llvm::json::fixUTF8(Doc);
diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h
index 2e3e0a4..01997ce 100644
--- a/clang-tools-extra/clangd/Config.h
+++ b/clang-tools-extra/clangd/Config.h
@@ -174,6 +174,9 @@ struct Config {
struct {
/// Whether hover show a.k.a type.
bool ShowAKA = true;
+ /// Limit the number of characters returned when hovering a macro;
+ /// 0 is no limit.
+ uint32_t MacroContentsLimit = 2048;
} Hover;
struct {
diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp
index 5dda6dd..962a48b 100644
--- a/clang-tools-extra/clangd/ConfigCompile.cpp
+++ b/clang-tools-extra/clangd/ConfigCompile.cpp
@@ -727,6 +727,12 @@ struct FragmentCompiler {
C.Hover.ShowAKA = ShowAKA;
});
}
+ if (F.MacroContentsLimit) {
+ Out.Apply.push_back(
+ [Limit(**F.MacroContentsLimit)](const Params &, Config &C) {
+ C.Hover.MacroContentsLimit = Limit;
+ });
+ }
}
void compile(Fragment::InlayHintsBlock &&F) {
diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h
index 0f11f37..2afeb36 100644
--- a/clang-tools-extra/clangd/ConfigFragment.h
+++ b/clang-tools-extra/clangd/ConfigFragment.h
@@ -361,6 +361,8 @@ struct Fragment {
struct HoverBlock {
/// Whether hover show a.k.a type.
std::optional<Located<bool>> ShowAKA;
+ /// Limit the number of characters returned when hovering a macro.
+ std::optional<Located<uint32_t>> MacroContentsLimit;
};
HoverBlock Hover;
diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp
index 289b7e8..392cf19 100644
--- a/clang-tools-extra/clangd/ConfigYAML.cpp
+++ b/clang-tools-extra/clangd/ConfigYAML.cpp
@@ -264,6 +264,10 @@ private:
if (auto ShowAKA = boolValue(N, "ShowAKA"))
F.ShowAKA = *ShowAKA;
});
+ Dict.handle("MacroContentsLimit", [&](Node &N) {
+ if (auto MacroContentsLimit = uint32Value(N, "MacroContentsLimit"))
+ F.MacroContentsLimit = *MacroContentsLimit;
+ });
Dict.parse(N);
}
diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp
index c6075e7..9a8d41d 100644
--- a/clang-tools-extra/clangd/DumpAST.cpp
+++ b/clang-tools-extra/clangd/DumpAST.cpp
@@ -147,17 +147,17 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
}
llvm_unreachable("Unhandled ArgKind enum");
}
- std::string getKind(const NestedNameSpecifierLoc &NNSL) {
- assert(NNSL.getNestedNameSpecifier());
- switch (NNSL.getNestedNameSpecifier()->getKind()) {
+ std::string getKind(NestedNameSpecifierLoc NNSL) {
+ switch (NNSL.getNestedNameSpecifier().getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("unexpected null nested name specifier");
#define NNS_KIND(X) \
- case NestedNameSpecifier::X: \
+ case NestedNameSpecifier::Kind::X: \
return #X
- NNS_KIND(Identifier);
NNS_KIND(Namespace);
- NNS_KIND(TypeSpec);
+ NNS_KIND(Type);
NNS_KIND(Global);
- NNS_KIND(Super);
+ NNS_KIND(MicrosoftSuper);
#undef NNS_KIND
}
llvm_unreachable("Unhandled SpecifierKind enum");
@@ -261,7 +261,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
return TL.getType().getLocalQualifiers().getAsString(
Ctx.getPrintingPolicy());
if (const auto *TT = dyn_cast<TagType>(TL.getTypePtr()))
- return getDetail(TT->getDecl());
+ return getDetail(TT->getOriginalDecl());
if (const auto *DT = dyn_cast<DeducedType>(TL.getTypePtr()))
if (DT->isDeduced())
return DT->getDeducedType().getAsString(Ctx.getPrintingPolicy());
@@ -273,16 +273,11 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
return getDetail(TT->getDecl());
return "";
}
- std::string getDetail(const NestedNameSpecifierLoc &NNSL) {
- const auto &NNS = *NNSL.getNestedNameSpecifier();
- switch (NNS.getKind()) {
- case NestedNameSpecifier::Identifier:
- return NNS.getAsIdentifier()->getName().str() + "::";
- case NestedNameSpecifier::Namespace:
- return NNS.getAsNamespace()->getNameAsString() + "::";
- default:
+ std::string getDetail(NestedNameSpecifierLoc NNSL) {
+ NestedNameSpecifier NNS = NNSL.getNestedNameSpecifier();
+ if (NNS.getKind() != NestedNameSpecifier::Kind::Namespace)
return "";
- }
+ return NNS.getAsNamespaceAndPrefix().Namespace->getNameAsString() + "::";
}
std::string getDetail(const CXXCtorInitializer *CCI) {
if (FieldDecl *FD = CCI->getAnyMember())
@@ -346,8 +341,10 @@ public:
return !D || isInjectedClassName(D) ||
traverseNode("declaration", D, [&] { Base::TraverseDecl(D); });
}
- bool TraverseTypeLoc(TypeLoc TL) {
- return !TL || traverseNode("type", TL, [&] { Base::TraverseTypeLoc(TL); });
+ bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
+ return !TL || traverseNode("type", TL, [&] {
+ Base::TraverseTypeLoc(TL, TraverseQualifier);
+ });
}
bool TraverseTemplateName(const TemplateName &TN) {
return traverseNode("template name", TN,
@@ -389,11 +386,11 @@ public:
// This means we'd never see 'int' in 'const int'! Work around that here.
// (The reason for the behavior is to avoid traversing the nested Type twice,
// but we ignore TraverseType anyway).
- bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL) {
+ bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL, bool TraverseQualifier) {
return TraverseTypeLoc(QTL.getUnqualifiedLoc());
}
// Uninteresting parts of the AST that don't have locations within them.
- bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; }
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; }
bool TraverseType(QualType) { return true; }
// OpaqueValueExpr blocks traversal, we must explicitly traverse it.
@@ -420,7 +417,7 @@ ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens,
V.TraverseNestedNameSpecifierLoc(
*const_cast<NestedNameSpecifierLoc *>(NNSL));
else if (const auto *NNS = N.get<NestedNameSpecifier>())
- V.TraverseNestedNameSpecifier(const_cast<NestedNameSpecifier *>(NNS));
+ V.TraverseNestedNameSpecifier(*NNS);
else if (const auto *TL = N.get<TypeLoc>())
V.TraverseTypeLoc(*const_cast<TypeLoc *>(TL));
else if (const auto *QT = N.get<QualType>())
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index b108957..32018d1 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -366,19 +366,11 @@ public:
Visitor(TargetFinder &Outer, RelSet Flags) : Outer(Outer), Flags(Flags) {}
void VisitTagType(const TagType *TT) {
- Outer.add(TT->getAsTagDecl(), Flags);
- }
-
- void VisitElaboratedType(const ElaboratedType *ET) {
- Outer.add(ET->desugar(), Flags);
+ Outer.add(cast<TagType>(TT)->getOriginalDecl(), Flags);
}
void VisitUsingType(const UsingType *ET) {
- Outer.add(ET->getFoundDecl(), Flags);
- }
-
- void VisitInjectedClassNameType(const InjectedClassNameType *ICNT) {
- Outer.add(ICNT->getDecl(), Flags);
+ Outer.add(ET->getDecl(), Flags);
}
void VisitDecltypeType(const DecltypeType *DTT) {
@@ -483,30 +475,27 @@ public:
Visitor(*this, Flags).Visit(T.getTypePtr());
}
- void add(const NestedNameSpecifier *NNS, RelSet Flags) {
+ void add(NestedNameSpecifier NNS, RelSet Flags) {
if (!NNS)
return;
- debug(*NNS, Flags);
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Namespace:
- add(NNS->getAsNamespace(), Flags);
- return;
- case NestedNameSpecifier::Identifier:
- if (Resolver) {
- add(Resolver->resolveNestedNameSpecifierToType(NNS), Flags);
- }
+ debug(NNS, Flags);
+ switch (NNS.getKind()) {
+ case NestedNameSpecifier::Kind::Namespace:
+ add(NNS.getAsNamespaceAndPrefix().Namespace, Flags);
return;
- case NestedNameSpecifier::TypeSpec:
- add(QualType(NNS->getAsType(), 0), Flags);
+ case NestedNameSpecifier::Kind::Type:
+ add(QualType(NNS.getAsType(), 0), Flags);
return;
- case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Kind::Global:
// This should be TUDecl, but we can't get a pointer to it!
return;
- case NestedNameSpecifier::Super:
- add(NNS->getAsRecordDecl(), Flags);
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ add(NNS.getAsMicrosoftSuper(), Flags);
return;
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("unexpected null nested name specifier");
}
- llvm_unreachable("unhandled NestedNameSpecifier::SpecifierKind");
+ llvm_unreachable("unhandled NestedNameSpecifier::Kind");
}
void add(const CXXCtorInitializer *CCI, RelSet Flags) {
@@ -555,7 +544,7 @@ allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver) {
else if (const NestedNameSpecifierLoc *NNSL = N.get<NestedNameSpecifierLoc>())
Finder.add(NNSL->getNestedNameSpecifier(), Flags);
else if (const NestedNameSpecifier *NNS = N.get<NestedNameSpecifier>())
- Finder.add(NNS, Flags);
+ Finder.add(*NNS, Flags);
else if (const TypeLoc *TL = N.get<TypeLoc>())
Finder.add(TL->getType(), Flags);
else if (const QualType *QT = N.get<QualType>())
@@ -861,32 +850,25 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
const HeuristicResolver *Resolver;
llvm::SmallVector<ReferenceLoc> Refs;
- void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) {
- // We only know about qualifier, rest if filled by inner locations.
- size_t InitialSize = Refs.size();
- Visit(L.getNamedTypeLoc().getUnqualifiedLoc());
- size_t NewSize = Refs.size();
- // Add qualifier for the newly-added refs.
- for (unsigned I = InitialSize; I < NewSize; ++I) {
- ReferenceLoc *Ref = &Refs[I];
- // Fill in the qualifier.
- assert(!Ref->Qualifier.hasQualifier() && "qualifier already set");
- Ref->Qualifier = L.getQualifierLoc();
- }
+ void VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc L) {
+ Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
+ L.getLocalSourceRange().getBegin(),
+ /*IsDecl=*/false,
+ {L.getDecl()}});
}
void VisitUsingTypeLoc(UsingTypeLoc L) {
- Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
+ Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
L.getLocalSourceRange().getBegin(),
/*IsDecl=*/false,
- {L.getFoundDecl()}});
+ {L.getDecl()}});
}
void VisitTagTypeLoc(TagTypeLoc L) {
- Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
+ Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
L.getNameLoc(),
/*IsDecl=*/false,
- {L.getDecl()}});
+ {L.getOriginalDecl()}});
}
void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) {
@@ -906,25 +888,18 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
// 2. 'vector<int>' with mask 'Underlying'.
// we want to return only #1 in this case.
Refs.push_back(ReferenceLoc{
- NestedNameSpecifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false,
+ L.getQualifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false,
explicitReferenceTargets(DynTypedNode::create(L.getType()),
DeclRelation::Alias, Resolver)});
}
void VisitDeducedTemplateSpecializationTypeLoc(
DeducedTemplateSpecializationTypeLoc L) {
Refs.push_back(ReferenceLoc{
- NestedNameSpecifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
+ L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
explicitReferenceTargets(DynTypedNode::create(L.getType()),
DeclRelation::Alias, Resolver)});
}
- void VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
- Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
- TL.getNameLoc(),
- /*IsDecl=*/false,
- {TL.getDecl()}});
- }
-
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc L) {
Refs.push_back(
@@ -943,12 +918,12 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
}
void VisitTypedefTypeLoc(TypedefTypeLoc L) {
- if (shouldSkipTypedef(L.getTypedefNameDecl()))
+ if (shouldSkipTypedef(L.getDecl()))
return;
- Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
+ Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
L.getNameLoc(),
/*IsDecl=*/false,
- {L.getTypedefNameDecl()}});
+ {L.getDecl()}});
}
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc L) {
@@ -980,17 +955,6 @@ public:
return true;
}
- bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc L) {
- // ElaboratedTypeLoc will reports information for its inner type loc.
- // Otherwise we loose information about inner types loc's qualifier.
- TypeLoc Inner = L.getNamedTypeLoc().getUnqualifiedLoc();
- if (L.getBeginLoc() == Inner.getBeginLoc())
- return RecursiveASTVisitor::TraverseTypeLoc(Inner);
- else
- TypeLocsToSkip.insert(Inner.getBeginLoc());
- return RecursiveASTVisitor::TraverseElaboratedTypeLoc(L);
- }
-
bool VisitStmt(Stmt *S) {
visitNode(DynTypedNode::create(*S));
return true;
@@ -1051,7 +1015,7 @@ public:
return true;
visitNode(DynTypedNode::create(L));
// Inner type is missing information about its qualifier, skip it.
- if (auto TL = L.getTypeLoc())
+ if (auto TL = L.getAsTypeLoc())
TypeLocsToSkip.insert(TL.getBeginLoc());
return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(L);
}
@@ -1092,12 +1056,21 @@ private:
if (auto *S = N.get<Stmt>())
return refInStmt(S, Resolver);
if (auto *NNSL = N.get<NestedNameSpecifierLoc>()) {
- // (!) 'DeclRelation::Alias' ensures we do not loose namespace aliases.
- return {ReferenceLoc{
- NNSL->getPrefix(), NNSL->getLocalBeginLoc(), false,
- explicitReferenceTargets(
- DynTypedNode::create(*NNSL->getNestedNameSpecifier()),
- DeclRelation::Alias, Resolver)}};
+ // (!) 'DeclRelation::Alias' ensures we do not lose namespace aliases.
+ NestedNameSpecifierLoc Qualifier;
+ SourceLocation NameLoc;
+ if (auto TL = NNSL->getAsTypeLoc()) {
+ Qualifier = TL.getPrefix();
+ NameLoc = TL.getNonPrefixBeginLoc();
+ } else {
+ Qualifier = NNSL->getAsNamespaceAndPrefix().Prefix;
+ NameLoc = NNSL->getLocalBeginLoc();
+ }
+ return {
+ ReferenceLoc{Qualifier, NameLoc, false,
+ explicitReferenceTargets(
+ DynTypedNode::create(NNSL->getNestedNameSpecifier()),
+ DeclRelation::Alias, Resolver)}};
}
if (const TypeLoc *TL = N.get<TypeLoc>())
return refInTypeLoc(*TL, Resolver);
@@ -1210,8 +1183,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceLoc R) {
OS << "}";
if (R.Qualifier) {
OS << ", qualifier = '";
- R.Qualifier.getNestedNameSpecifier()->print(OS,
- PrintingPolicy(LangOptions()));
+ R.Qualifier.getNestedNameSpecifier().print(OS,
+ PrintingPolicy(LangOptions()));
OS << "'";
}
if (R.IsDecl)
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index 7c0eb96..c6afd0b 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -833,6 +833,10 @@ bool OverlayCDB::setCompileCommand(PathRef File,
std::unique_ptr<ProjectModules>
OverlayCDB::getProjectModules(PathRef File) const {
auto MDB = DelegatingCDB::getProjectModules(File);
+ if (!MDB) {
+ log("Failed to get compilation Database for {0}", File);
+ return {};
+ }
MDB->setCommandMangler([&Mangler = Mangler](tooling::CompileCommand &Command,
PathRef CommandPath) {
Mangler(Command, CommandPath);
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 1e0718d..9eec322 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -18,6 +18,7 @@
#include "Protocol.h"
#include "Selection.h"
#include "SourceCode.h"
+#include "SymbolDocumentation.h"
#include "clang-include-cleaner/Analysis.h"
#include "clang-include-cleaner/IncludeSpeller.h"
#include "clang-include-cleaner/Types.h"
@@ -41,6 +42,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
@@ -170,13 +172,14 @@ HoverInfo::PrintedType printType(QualType QT, ASTContext &ASTCtx,
QT = QT->castAs<DecltypeType>()->getUnderlyingType();
HoverInfo::PrintedType Result;
llvm::raw_string_ostream OS(Result.Type);
- // Special case: if the outer type is a tag type without qualifiers, then
- // include the tag for extra clarity.
- // This isn't very idiomatic, so don't attempt it for complex cases, including
- // pointers/references, template specializations, etc.
+ // Special case: if the outer type is a canonical tag type, then include the
+ // tag for extra clarity. This isn't very idiomatic, so don't attempt it for
+ // complex cases, including pointers/references, template specializations,
+ // etc.
if (!QT.isNull() && !QT.hasQualifiers() && PP.SuppressTagKeyword) {
- if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr()))
- OS << TT->getDecl()->getKindName() << " ";
+ if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr());
+ TT && TT->isCanonicalUnqualified())
+ OS << TT->getOriginalDecl()->getKindName() << " ";
}
QT.print(OS, PP);
@@ -451,8 +454,7 @@ std::optional<std::string> printExprValue(const Expr *E,
Constant.Val.getInt().getSignificantBits() <= 64) {
// Compare to int64_t to avoid bit-width match requirements.
int64_t Val = Constant.Val.getInt().getExtValue();
- for (const EnumConstantDecl *ECD :
- T->castAs<EnumType>()->getDecl()->enumerators())
+ for (const EnumConstantDecl *ECD : T->castAsEnumDecl()->enumerators())
if (ECD->getInitVal() == Val)
return llvm::formatv("{0} ({1})", ECD->getNameAsString(),
printHex(Constant.Val.getInt()))
@@ -627,6 +629,9 @@ HoverInfo getHoverContents(const NamedDecl *D, const PrintingPolicy &PP,
HI.Name = printName(Ctx, *D);
const auto *CommentD = getDeclForComment(D);
HI.Documentation = getDeclComment(Ctx, *CommentD);
+ // save the language options to be able to create the comment::CommandTraits
+ // to parse the documentation
+ HI.CommentOpts = D->getASTContext().getLangOpts().CommentOpts;
enhanceFromIndex(HI, *CommentD, Index);
if (HI.Documentation.empty())
HI.Documentation = synthesizeDocumentation(D);
@@ -789,7 +794,9 @@ HoverInfo getHoverContents(const DefinedMacro &Macro, const syntax::Token &Tok,
for (const auto &ExpandedTok : Expansion->Expanded) {
ExpansionText += ExpandedTok.text(SM);
ExpansionText += " ";
- if (ExpansionText.size() > 2048) {
+ const Config &Cfg = Config::current();
+ const size_t Limit = static_cast<size_t>(Cfg.Hover.MacroContentsLimit);
+ if (Limit && ExpansionText.size() > Limit) {
ExpansionText.clear();
break;
}
@@ -826,7 +833,7 @@ std::optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE,
ASTContext &ASTCtx,
const PrintingPolicy &PP) {
QualType OriginThisType = CTE->getType()->getPointeeType();
- QualType ClassType = declaredType(OriginThisType->getAsTagDecl());
+ QualType ClassType = declaredType(OriginThisType->castAsTagDecl());
// For partial specialization class, origin `this` pointee type will be
// parsed as `InjectedClassNameType`, which will ouput template arguments
// like "type-parameter-0-0". So we retrieve user written class type in this
@@ -967,10 +974,11 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
const auto &Ctx = ND.getASTContext();
if (auto *RD = llvm::dyn_cast<RecordDecl>(&ND)) {
- if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RD->getTypeForDecl()))
+ CanQualType RT = Ctx.getCanonicalTagType(RD);
+ if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RT))
HI.Size = Size->getQuantity() * 8;
if (!RD->isDependentType() && RD->isCompleteDefinition())
- HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl());
+ HI.Align = Ctx.getTypeAlign(RT);
return;
}
@@ -1267,10 +1275,10 @@ std::optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
HoverCountMetric.record(1, "include");
HoverInfo HI;
HI.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
- // FIXME: We don't have a fitting value for Kind.
HI.Definition =
URIForFile::canonicalize(Inc.Resolved, AST.tuPath()).file().str();
HI.DefinitionLanguage = "";
+ HI.Kind = index::SymbolKind::IncludeDirective;
maybeAddUsedSymbols(AST, HI, Inc);
return HI;
}
@@ -1388,9 +1396,241 @@ static std::string formatOffset(uint64_t OffsetInBits) {
return Offset;
}
-markup::Document HoverInfo::present() const {
+void HoverInfo::calleeArgInfoToMarkupParagraph(markup::Paragraph &P) const {
+ assert(CallPassType);
+ std::string Buffer;
+ llvm::raw_string_ostream OS(Buffer);
+ OS << "Passed ";
+ if (CallPassType->PassBy != HoverInfo::PassType::Value) {
+ OS << "by ";
+ if (CallPassType->PassBy == HoverInfo::PassType::ConstRef)
+ OS << "const ";
+ OS << "reference ";
+ }
+ if (CalleeArgInfo->Name)
+ OS << "as " << CalleeArgInfo->Name;
+ else if (CallPassType->PassBy == HoverInfo::PassType::Value)
+ OS << "by value";
+ if (CallPassType->Converted && CalleeArgInfo->Type)
+ OS << " (converted to " << CalleeArgInfo->Type->Type << ")";
+ P.appendText(OS.str());
+}
+
+void HoverInfo::usedSymbolNamesToMarkup(markup::Document &Output) const {
+ markup::Paragraph &P = Output.addParagraph();
+ P.appendText("provides ");
+
+ const std::vector<std::string>::size_type SymbolNamesLimit = 5;
+ auto Front = llvm::ArrayRef(UsedSymbolNames).take_front(SymbolNamesLimit);
+
+ llvm::interleave(
+ Front, [&](llvm::StringRef Sym) { P.appendCode(Sym); },
+ [&] { P.appendText(", "); });
+ if (UsedSymbolNames.size() > Front.size()) {
+ P.appendText(" and ");
+ P.appendText(std::to_string(UsedSymbolNames.size() - Front.size()));
+ P.appendText(" more");
+ }
+}
+
+void HoverInfo::providerToMarkupParagraph(markup::Document &Output) const {
+ markup::Paragraph &DI = Output.addParagraph();
+ DI.appendText("provided by");
+ DI.appendSpace();
+ DI.appendCode(Provider);
+}
+
+void HoverInfo::definitionScopeToMarkup(markup::Document &Output) const {
+ std::string Buffer;
+
+ // Append scope comment, dropping trailing "::".
+ // Note that we don't print anything for global namespace, to not annoy
+ // non-c++ projects or projects that are not making use of namespaces.
+ if (!LocalScope.empty()) {
+ // Container name, e.g. class, method, function.
+ // We might want to propagate some info about container type to print
+ // function foo, class X, method X::bar, etc.
+ Buffer += "// In " + llvm::StringRef(LocalScope).rtrim(':').str() + '\n';
+ } else if (NamespaceScope && !NamespaceScope->empty()) {
+ Buffer += "// In namespace " +
+ llvm::StringRef(*NamespaceScope).rtrim(':').str() + '\n';
+ }
+
+ if (!AccessSpecifier.empty()) {
+ Buffer += AccessSpecifier + ": ";
+ }
+
+ Buffer += Definition;
+
+ Output.addCodeBlock(Buffer, DefinitionLanguage);
+}
+
+void HoverInfo::valueToMarkupParagraph(markup::Paragraph &P) const {
+ P.appendText("Value = ");
+ P.appendCode(*Value);
+}
+
+void HoverInfo::offsetToMarkupParagraph(markup::Paragraph &P) const {
+ P.appendText("Offset: " + formatOffset(*Offset));
+}
+
+void HoverInfo::sizeToMarkupParagraph(markup::Paragraph &P) const {
+ P.appendText("Size: " + formatSize(*Size));
+ if (Padding && *Padding != 0) {
+ P.appendText(llvm::formatv(" (+{0} padding)", formatSize(*Padding)).str());
+ }
+ if (Align)
+ P.appendText(", alignment " + formatSize(*Align));
+}
+
+markup::Document HoverInfo::presentDoxygen() const {
+
markup::Document Output;
+ // Header contains a text of the form:
+ // variable `var`
+ //
+ // class `X`
+ //
+ // function `foo`
+ //
+ // expression
+ //
+ // Note that we are making use of a level-3 heading because VSCode renders
+ // level 1 and 2 headers in a huge font, see
+ // https://github.com/microsoft/vscode/issues/88417 for details.
+ markup::Paragraph &Header = Output.addHeading(3);
+ if (Kind != index::SymbolKind::Unknown &&
+ Kind != index::SymbolKind::IncludeDirective)
+ Header.appendText(index::getSymbolKindString(Kind)).appendSpace();
+ assert(!Name.empty() && "hover triggered on a nameless symbol");
+
+ if (Kind == index::SymbolKind::IncludeDirective) {
+ Header.appendCode(Name);
+
+ if (!Definition.empty())
+ Output.addParagraph().appendCode(Definition);
+
+ if (!UsedSymbolNames.empty()) {
+ Output.addRuler();
+ usedSymbolNamesToMarkup(Output);
+ }
+
+ return Output;
+ }
+
+ if (!Definition.empty()) {
+ Output.addRuler();
+ definitionScopeToMarkup(Output);
+ } else {
+ Header.appendCode(Name);
+ }
+
+ if (!Provider.empty()) {
+ providerToMarkupParagraph(Output);
+ }
+
+ // Put a linebreak after header to increase readability.
+ Output.addRuler();
+
+ SymbolDocCommentVisitor SymbolDoc(Documentation, CommentOpts);
+
+ if (SymbolDoc.hasBriefCommand()) {
+ SymbolDoc.briefToMarkup(Output.addParagraph());
+ Output.addRuler();
+ }
+
+ // For functions we display signature in a list form, e.g.:
+ // Template Parameters:
+ // - `typename T` - description
+ // Parameters:
+ // - `bool param1` - description
+ // - `int param2 = 5` - description
+ // Returns
+ // `type` - description
+ if (TemplateParameters && !TemplateParameters->empty()) {
+ Output.addParagraph().appendBoldText("Template Parameters:");
+ markup::BulletList &L = Output.addBulletList();
+ for (const auto &Param : *TemplateParameters) {
+ markup::Paragraph &P = L.addItem().addParagraph();
+ P.appendCode(llvm::to_string(Param));
+ if (SymbolDoc.isTemplateTypeParmDocumented(llvm::to_string(Param.Name))) {
+ P.appendText(" - ");
+ SymbolDoc.templateTypeParmDocToMarkup(llvm::to_string(Param.Name), P);
+ }
+ }
+ Output.addRuler();
+ }
+
+ if (Parameters && !Parameters->empty()) {
+ Output.addParagraph().appendBoldText("Parameters:");
+ markup::BulletList &L = Output.addBulletList();
+ for (const auto &Param : *Parameters) {
+ markup::Paragraph &P = L.addItem().addParagraph();
+ P.appendCode(llvm::to_string(Param));
+
+ if (SymbolDoc.isParameterDocumented(llvm::to_string(Param.Name))) {
+ P.appendText(" - ");
+ SymbolDoc.parameterDocToMarkup(llvm::to_string(Param.Name), P);
+ }
+ }
+ Output.addRuler();
+ }
+
+ // Print Types on their own lines to reduce chances of getting line-wrapped by
+ // editor, as they might be long.
+ if (ReturnType &&
+ ((ReturnType->Type != "void" && !ReturnType->AKA.has_value()) ||
+ (ReturnType->AKA.has_value() && ReturnType->AKA != "void"))) {
+ Output.addParagraph().appendBoldText("Returns:");
+ markup::Paragraph &P = Output.addParagraph();
+ P.appendCode(llvm::to_string(*ReturnType));
+
+ if (SymbolDoc.hasReturnCommand()) {
+ P.appendText(" - ");
+ SymbolDoc.returnToMarkup(P);
+ }
+ Output.addRuler();
+ }
+
+ // add specially handled doxygen commands.
+ SymbolDoc.warningsToMarkup(Output);
+ SymbolDoc.notesToMarkup(Output);
+
+ // add any other documentation.
+ SymbolDoc.docToMarkup(Output);
+
+ Output.addRuler();
+
+ // Don't print Type after Parameters or ReturnType as this will just duplicate
+ // the information
+ if (Type && !ReturnType && !Parameters)
+ Output.addParagraph().appendText("Type: ").appendCode(
+ llvm::to_string(*Type));
+ if (Value) {
+ valueToMarkupParagraph(Output.addParagraph());
+ }
+
+ if (Offset)
+ offsetToMarkupParagraph(Output.addParagraph());
+ if (Size) {
+ sizeToMarkupParagraph(Output.addParagraph());
+ }
+
+ if (CalleeArgInfo) {
+ calleeArgInfoToMarkupParagraph(Output.addParagraph());
+ }
+
+ if (!UsedSymbolNames.empty()) {
+ Output.addRuler();
+ usedSymbolNamesToMarkup(Output);
+ }
+
+ return Output;
+}
+
+markup::Document HoverInfo::presentDefault() const {
+ markup::Document Output;
// Header contains a text of the form:
// variable `var`
//
@@ -1404,17 +1644,14 @@ markup::Document HoverInfo::present() const {
// level 1 and 2 headers in a huge font, see
// https://github.com/microsoft/vscode/issues/88417 for details.
markup::Paragraph &Header = Output.addHeading(3);
- if (Kind != index::SymbolKind::Unknown)
+ if (Kind != index::SymbolKind::Unknown &&
+ Kind != index::SymbolKind::IncludeDirective)
Header.appendText(index::getSymbolKindString(Kind)).appendSpace();
assert(!Name.empty() && "hover triggered on a nameless symbol");
Header.appendCode(Name);
if (!Provider.empty()) {
- markup::Paragraph &DI = Output.addParagraph();
- DI.appendText("provided by");
- DI.appendSpace();
- DI.appendCode(Provider);
- Output.addRuler();
+ providerToMarkupParagraph(Output);
}
// Put a linebreak after header to increase readability.
@@ -1432,7 +1669,7 @@ markup::Document HoverInfo::present() const {
}
if (Parameters && !Parameters->empty()) {
- Output.addParagraph().appendText("Parameters: ");
+ Output.addParagraph().appendText("Parameters:");
markup::BulletList &L = Output.addBulletList();
for (const auto &Param : *Parameters)
L.addItem().addParagraph().appendCode(llvm::to_string(Param));
@@ -1445,41 +1682,17 @@ markup::Document HoverInfo::present() const {
llvm::to_string(*Type));
if (Value) {
- markup::Paragraph &P = Output.addParagraph();
- P.appendText("Value = ");
- P.appendCode(*Value);
+ valueToMarkupParagraph(Output.addParagraph());
}
if (Offset)
- Output.addParagraph().appendText("Offset: " + formatOffset(*Offset));
+ offsetToMarkupParagraph(Output.addParagraph());
if (Size) {
- auto &P = Output.addParagraph().appendText("Size: " + formatSize(*Size));
- if (Padding && *Padding != 0) {
- P.appendText(
- llvm::formatv(" (+{0} padding)", formatSize(*Padding)).str());
- }
- if (Align)
- P.appendText(", alignment " + formatSize(*Align));
+ sizeToMarkupParagraph(Output.addParagraph());
}
if (CalleeArgInfo) {
- assert(CallPassType);
- std::string Buffer;
- llvm::raw_string_ostream OS(Buffer);
- OS << "Passed ";
- if (CallPassType->PassBy != HoverInfo::PassType::Value) {
- OS << "by ";
- if (CallPassType->PassBy == HoverInfo::PassType::ConstRef)
- OS << "const ";
- OS << "reference ";
- }
- if (CalleeArgInfo->Name)
- OS << "as " << CalleeArgInfo->Name;
- else if (CallPassType->PassBy == HoverInfo::PassType::Value)
- OS << "by value";
- if (CallPassType->Converted && CalleeArgInfo->Type)
- OS << " (converted to " << CalleeArgInfo->Type->Type << ")";
- Output.addParagraph().appendText(OS.str());
+ calleeArgInfoToMarkupParagraph(Output.addParagraph());
}
if (!Documentation.empty())
@@ -1487,49 +1700,12 @@ markup::Document HoverInfo::present() const {
if (!Definition.empty()) {
Output.addRuler();
- std::string Buffer;
-
- if (!Definition.empty()) {
- // Append scope comment, dropping trailing "::".
- // Note that we don't print anything for global namespace, to not annoy
- // non-c++ projects or projects that are not making use of namespaces.
- if (!LocalScope.empty()) {
- // Container name, e.g. class, method, function.
- // We might want to propagate some info about container type to print
- // function foo, class X, method X::bar, etc.
- Buffer +=
- "// In " + llvm::StringRef(LocalScope).rtrim(':').str() + '\n';
- } else if (NamespaceScope && !NamespaceScope->empty()) {
- Buffer += "// In namespace " +
- llvm::StringRef(*NamespaceScope).rtrim(':').str() + '\n';
- }
-
- if (!AccessSpecifier.empty()) {
- Buffer += AccessSpecifier + ": ";
- }
-
- Buffer += Definition;
- }
-
- Output.addCodeBlock(Buffer, DefinitionLanguage);
+ definitionScopeToMarkup(Output);
}
if (!UsedSymbolNames.empty()) {
Output.addRuler();
- markup::Paragraph &P = Output.addParagraph();
- P.appendText("provides ");
-
- const std::vector<std::string>::size_type SymbolNamesLimit = 5;
- auto Front = llvm::ArrayRef(UsedSymbolNames).take_front(SymbolNamesLimit);
-
- llvm::interleave(
- Front, [&](llvm::StringRef Sym) { P.appendCode(Sym); },
- [&] { P.appendText(", "); });
- if (UsedSymbolNames.size() > Front.size()) {
- P.appendText(" and ");
- P.appendText(std::to_string(UsedSymbolNames.size() - Front.size()));
- P.appendText(" more");
- }
+ usedSymbolNamesToMarkup(Output);
}
return Output;
@@ -1538,21 +1714,19 @@ markup::Document HoverInfo::present() const {
std::string HoverInfo::present(MarkupKind Kind) const {
if (Kind == MarkupKind::Markdown) {
const Config &Cfg = Config::current();
- if ((Cfg.Documentation.CommentFormat ==
- Config::CommentFormatPolicy::Markdown) ||
- (Cfg.Documentation.CommentFormat ==
- Config::CommentFormatPolicy::Doxygen))
- // If the user prefers Markdown, we use the present() method to generate
- // the Markdown output.
- return present().asMarkdown();
+ if (Cfg.Documentation.CommentFormat ==
+ Config::CommentFormatPolicy::Markdown)
+ return presentDefault().asMarkdown();
+ if (Cfg.Documentation.CommentFormat == Config::CommentFormatPolicy::Doxygen)
+ return presentDoxygen().asMarkdown();
if (Cfg.Documentation.CommentFormat ==
Config::CommentFormatPolicy::PlainText)
// If the user prefers plain text, we use the present() method to generate
// the plain text output.
- return present().asEscapedMarkdown();
+ return presentDefault().asEscapedMarkdown();
}
- return present().asPlainText();
+ return presentDefault().asPlainText();
}
// If the backtick at `Offset` starts a probable quoted range, return the range
diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h
index 2f65431..614180a 100644
--- a/clang-tools-extra/clangd/Hover.h
+++ b/clang-tools-extra/clangd/Hover.h
@@ -74,6 +74,8 @@ struct HoverInfo {
std::optional<Range> SymRange;
index::SymbolKind Kind = index::SymbolKind::Unknown;
std::string Documentation;
+ // required to create a comments::CommandTraits object without the ASTContext
+ CommentOptions CommentOpts;
/// Source code containing the definition of the symbol.
std::string Definition;
const char *DefinitionLanguage = "cpp";
@@ -118,10 +120,23 @@ struct HoverInfo {
// alphabetical order.
std::vector<std::string> UsedSymbolNames;
- /// Produce a user-readable information.
- markup::Document present() const;
-
+ /// Produce a user-readable information based on the specified markup kind.
std::string present(MarkupKind Kind) const;
+
+private:
+ void usedSymbolNamesToMarkup(markup::Document &Output) const;
+ void providerToMarkupParagraph(markup::Document &Output) const;
+ void definitionScopeToMarkup(markup::Document &Output) const;
+ void calleeArgInfoToMarkupParagraph(markup::Paragraph &P) const;
+ void valueToMarkupParagraph(markup::Paragraph &P) const;
+ void offsetToMarkupParagraph(markup::Paragraph &P) const;
+ void sizeToMarkupParagraph(markup::Paragraph &P) const;
+
+ /// Parse and render the hover information as Doxygen documentation.
+ markup::Document presentDoxygen() const;
+
+ /// Render the hover information as a default documentation.
+ markup::Document presentDefault() const;
};
inline bool operator==(const HoverInfo::PrintedType &LHS,
diff --git a/clang-tools-extra/clangd/IncludeFixer.cpp b/clang-tools-extra/clangd/IncludeFixer.cpp
index 50bc2bd..c27d960 100644
--- a/clang-tools-extra/clangd/IncludeFixer.cpp
+++ b/clang-tools-extra/clangd/IncludeFixer.cpp
@@ -173,7 +173,7 @@ std::vector<Fix> IncludeFixer::fix(DiagnosticsEngine::Level DiagLevel,
// `enum x : int;' is not formally an incomplete type.
// We may need a full definition anyway.
if (auto * ET = llvm::dyn_cast<EnumType>(T))
- if (!ET->getDecl()->getDefinition())
+ if (!ET->getOriginalDecl()->getDefinition())
return fixIncompleteType(*T);
}
}
@@ -400,35 +400,35 @@ std::optional<CheapUnresolvedName> extractUnresolvedNameCheaply(
CheapUnresolvedName Result;
Result.Name = Unresolved.getAsString();
if (SS && SS->isNotEmpty()) { // "::" or "ns::"
- if (auto *Nested = SS->getScopeRep()) {
- if (Nested->getKind() == NestedNameSpecifier::Global) {
- Result.ResolvedScope = "";
- } else if (const NamespaceBaseDecl *NSB = Nested->getAsNamespace()) {
- if (const auto *NS = dyn_cast<NamespaceDecl>(NSB)) {
- std::string SpecifiedNS = printNamespaceScope(*NS);
- std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM);
-
- // Check the specifier spelled in the source.
- // If the resolved scope doesn't end with the spelled scope, the
- // resolved scope may come from a sema typo correction. For example,
- // sema assumes that "clangd::" is a typo of "clang::" and uses
- // "clang::" as the specified scope in:
- // namespace clang { clangd::X; }
- // In this case, we use the "typo" specifier as extra scope instead
- // of using the scope assumed by sema.
- if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) {
- Result.ResolvedScope = std::move(SpecifiedNS);
- } else {
- Result.UnresolvedScope = std::move(*Spelling);
- }
+ NestedNameSpecifier Nested = SS->getScopeRep();
+ if (Nested.getKind() == NestedNameSpecifier::Kind::Global) {
+ Result.ResolvedScope = "";
+ } else if (Nested.getKind() == NestedNameSpecifier::Kind::Namespace) {
+ const NamespaceBaseDecl *NSB = Nested.getAsNamespaceAndPrefix().Namespace;
+ if (const auto *NS = dyn_cast<NamespaceDecl>(NSB)) {
+ std::string SpecifiedNS = printNamespaceScope(*NS);
+ std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM);
+
+ // Check the specifier spelled in the source.
+ // If the resolved scope doesn't end with the spelled scope, the
+ // resolved scope may come from a sema typo correction. For example,
+ // sema assumes that "clangd::" is a typo of "clang::" and uses
+ // "clang::" as the specified scope in:
+ // namespace clang { clangd::X; }
+ // In this case, we use the "typo" specifier as extra scope instead
+ // of using the scope assumed by sema.
+ if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) {
+ Result.ResolvedScope = std::move(SpecifiedNS);
} else {
- Result.ResolvedScope = printNamespaceScope(*cast<NamespaceAliasDecl>(NSB)->getNamespace());
+ Result.UnresolvedScope = std::move(*Spelling);
}
} else {
- // We don't fix symbols in scopes that are not top-level e.g. class
- // members, as we don't collect includes for them.
- return std::nullopt;
+ Result.ResolvedScope = printNamespaceScope(*cast<NamespaceAliasDecl>(NSB)->getNamespace());
}
+ } else {
+ // We don't fix symbols in scopes that are not top-level e.g. class
+ // members, as we don't collect includes for them.
+ return std::nullopt;
}
}
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 197c62c..cd479e1 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -55,18 +55,24 @@ void stripLeadingUnderscores(StringRef &Name) { Name = Name.ltrim('_'); }
// getDeclForType() returns the decl responsible for Type's spelling.
// This is the inverse of ASTContext::getTypeDeclType().
-template <typename Ty, typename = decltype(((Ty *)nullptr)->getDecl())>
-const NamedDecl *getDeclForTypeImpl(const Ty *T) {
- return T->getDecl();
-}
-const NamedDecl *getDeclForTypeImpl(const void *T) { return nullptr; }
const NamedDecl *getDeclForType(const Type *T) {
switch (T->getTypeClass()) {
-#define ABSTRACT_TYPE(TY, BASE)
-#define TYPE(TY, BASE) \
- case Type::TY: \
- return getDeclForTypeImpl(llvm::cast<TY##Type>(T));
-#include "clang/AST/TypeNodes.inc"
+ case Type::Enum:
+ case Type::Record:
+ case Type::InjectedClassName:
+ return cast<TagType>(T)->getOriginalDecl();
+ case Type::TemplateSpecialization:
+ return cast<TemplateSpecializationType>(T)
+ ->getTemplateName()
+ .getAsTemplateDecl(/*IgnoreDeduced=*/true);
+ case Type::Typedef:
+ return cast<TypedefType>(T)->getDecl();
+ case Type::UnresolvedUsing:
+ return cast<UnresolvedUsingType>(T)->getDecl();
+ case Type::Using:
+ return cast<UsingType>(T)->getDecl();
+ default:
+ return nullptr;
}
llvm_unreachable("Unknown TypeClass enum");
}
@@ -81,8 +87,6 @@ llvm::StringRef getSimpleName(const NamedDecl &D) {
return getSimpleName(D.getDeclName());
}
llvm::StringRef getSimpleName(QualType T) {
- if (const auto *ET = llvm::dyn_cast<ElaboratedType>(T))
- return getSimpleName(ET->getNamedType());
if (const auto *BT = llvm::dyn_cast<BuiltinType>(T)) {
PrintingPolicy PP(LangOptions{});
PP.adjustForCPlusPlus();
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index 56d00c2..64f22b9 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -14,6 +14,8 @@
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ModuleCache.h"
#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/CommandLine.h"
+
#include <queue>
namespace clang {
@@ -21,6 +23,12 @@ namespace clangd {
namespace {
+llvm::cl::opt<bool> DebugModulesBuilder(
+ "debug-modules-builder",
+ llvm::cl::desc("Don't remove clangd's built module files for debugging. "
+ "Remember to remove them later after debugging."),
+ llvm::cl::init(false));
+
// Create a path to store module files. Generally it should be:
//
// {TEMP_DIRS}/clangd/module_files/{hashed-file-name}-%%-%%-%%-%%-%%-%%/.
@@ -122,7 +130,7 @@ struct ModuleFile {
}
~ModuleFile() {
- if (!ModuleFilePath.empty())
+ if (!ModuleFilePath.empty() && !DebugModulesBuilder)
llvm::sys::fs::remove(ModuleFilePath);
}
@@ -315,7 +323,7 @@ buildModuleFile(llvm::StringRef ModuleName, PathRef ModuleUnitFileName,
Cmds += Arg;
}
- clangd::vlog("Failed to compile {0} with command: {1}.", ModuleUnitFileName,
+ clangd::vlog("Failed to compile {0} with command: {1}", ModuleUnitFileName,
Cmds);
std::string BuiltModuleFilesStr = BuiltModuleFiles.getAsString();
@@ -325,7 +333,10 @@ buildModuleFile(llvm::StringRef ModuleName, PathRef ModuleUnitFileName,
return llvm::createStringError(
llvm::formatv("Failed to compile {0}. Use '--log=verbose' to view "
- "detailed failure reasons.",
+ "detailed failure reasons. It is helpful to use "
+ "'--debug-modules-builder' flag to keep the clangd's "
+ "built module files to reproduce the failure for "
+ "debugging. Remember to remove them after debugging.",
ModuleUnitFileName));
}
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 2c858e2..560b8e0 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -297,6 +297,9 @@ SymbolKind adjustKindToCapability(SymbolKind Kind,
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) {
switch (Kind) {
+ // FIXME: for backwards compatibility, the include directive kind is treated
+ // the same as Unknown
+ case index::SymbolKind::IncludeDirective:
case index::SymbolKind::Unknown:
return SymbolKind::Variable;
case index::SymbolKind::Module:
diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp
index 3f630b0..dc4afe1 100644
--- a/clang-tools-extra/clangd/Quality.cpp
+++ b/clang-tools-extra/clangd/Quality.cpp
@@ -143,6 +143,9 @@ categorize(const index::SymbolInfo &D) {
case index::SymbolKind::Parameter:
case index::SymbolKind::NonTypeTemplateParm:
return SymbolQualitySignals::Variable;
+ // FIXME: for backwards compatibility, the include directive kind is treated
+ // the same as Unknown
+ case index::SymbolKind::IncludeDirective:
case index::SymbolKind::Using:
case index::SymbolKind::Module:
case index::SymbolKind::Unknown:
diff --git a/clang-tools-extra/clangd/ScanningProjectModules.cpp b/clang-tools-extra/clangd/ScanningProjectModules.cpp
index e561513..672e996 100644
--- a/clang-tools-extra/clangd/ScanningProjectModules.cpp
+++ b/clang-tools-extra/clangd/ScanningProjectModules.cpp
@@ -122,8 +122,17 @@ ModuleDependencyScanner::scan(PathRef FilePath,
ModuleDependencyInfo Result;
if (ScanningResult->Provides) {
- ModuleNameToSource[ScanningResult->Provides->ModuleName] = FilePath;
Result.ModuleName = ScanningResult->Provides->ModuleName;
+
+ auto [Iter, Inserted] = ModuleNameToSource.try_emplace(
+ ScanningResult->Provides->ModuleName, FilePath);
+
+ if (!Inserted && Iter->second != FilePath) {
+ elog("Detected multiple source files ({0}, {1}) declaring the same "
+ "module: '{2}'. "
+ "Now clangd may find the wrong source in such case.",
+ Iter->second, FilePath, ScanningResult->Provides->ModuleName);
+ }
}
for (auto &Required : ScanningResult->Requires)
diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp
index 277cb87..06165df 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -62,7 +62,8 @@ void recordMetrics(const SelectionTree &S, const LangOptions &Lang) {
}
// Return the range covering a node and all its children.
-SourceRange getSourceRange(const DynTypedNode &N) {
+SourceRange getSourceRange(const DynTypedNode &N,
+ bool IncludeQualifier = false) {
// MemberExprs to implicitly access anonymous fields should not claim any
// tokens for themselves. Given:
// struct A { struct { int b; }; };
@@ -80,7 +81,7 @@ SourceRange getSourceRange(const DynTypedNode &N) {
? getSourceRange(DynTypedNode::create(*ME->getBase()))
: SourceRange();
}
- return N.getSourceRange();
+ return N.getSourceRange(IncludeQualifier);
}
// An IntervalSet maintains a set of disjoint subranges of an array.
@@ -643,8 +644,9 @@ public:
}
return traverseNode(X, [&] { return Base::TraverseDecl(X); });
}
- bool TraverseTypeLoc(TypeLoc X) {
- return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); });
+ bool TraverseTypeLoc(TypeLoc X, bool TraverseQualifier = true) {
+ return traverseNode(
+ &X, [&] { return Base::TraverseTypeLoc(X, TraverseQualifier); });
}
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &X) {
return traverseNode(&X,
@@ -690,7 +692,8 @@ public:
// This means we'd never see 'int' in 'const int'! Work around that here.
// (The reason for the behavior is to avoid traversing the nested Type twice,
// but we ignore TraverseType anyway).
- bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QX) {
+ bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QX,
+ bool TraverseQualifier = true) {
return traverseNode<TypeLoc>(
&QX, [&] { return TraverseTypeLoc(QX.getUnqualifiedLoc()); });
}
@@ -698,7 +701,7 @@ public:
return traverseNode(&PL, [&] { return Base::TraverseObjCProtocolLoc(PL); });
}
// Uninteresting parts of the AST that don't have locations within them.
- bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; }
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; }
bool TraverseType(QualType) { return true; }
// The DeclStmt for the loop variable claims to cover the whole range
@@ -798,7 +801,7 @@ private:
// An optimization for a common case: nodes outside macro expansions that
// don't intersect the selection may be recursively skipped.
bool canSafelySkipNode(const DynTypedNode &N) {
- SourceRange S = getSourceRange(N);
+ SourceRange S = getSourceRange(N, /*IncludeQualifier=*/true);
if (auto *TL = N.get<TypeLoc>()) {
// FIXME: TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile
// heuristics. We should consider only pruning critical TypeLoc nodes, to
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index e6d5cf7..2b151b1 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -1127,21 +1127,6 @@ public:
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
}
- // findExplicitReferences will walk nested-name-specifiers and
- // find anything that can be resolved to a Decl. However, non-leaf
- // components of nested-name-specifiers which are dependent names
- // (kind "Identifier") cannot be resolved to a decl, so we visit
- // them here.
- bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) {
- if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) {
- if (NNS->getKind() == NestedNameSpecifier::Identifier)
- H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type)
- .addModifier(HighlightingModifier::DependentName)
- .addModifier(HighlightingModifier::ClassScope);
- }
- return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q);
- }
-
private:
HighlightingsBuilder &H;
};
diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp
index dd7116e..3353121 100644
--- a/clang-tools-extra/clangd/SemanticSelection.cpp
+++ b/clang-tools-extra/clangd/SemanticSelection.cpp
@@ -175,9 +175,8 @@ llvm::Expected<std::vector<FoldingRange>> getFoldingRanges(ParsedAST &AST) {
return collectFoldingRanges(SyntaxTree, TM);
}
-// FIXME( usaxena95): Collect PP conditional regions, includes and other code
-// regions (e.g. public/private/protected sections of classes, control flow
-// statement bodies).
+// FIXME( usaxena95): Collect includes and other code regions (e.g.
+// public/private/protected sections of classes, control flow statement bodies).
// Related issue: https://github.com/clangd/clangd/issues/310
llvm::Expected<std::vector<FoldingRange>>
getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
@@ -186,12 +185,6 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
auto DirectiveStructure = DirectiveTree::parse(OrigStream);
chooseConditionalBranches(DirectiveStructure, OrigStream);
- // FIXME: Provide ranges in the disabled-PP regions as well.
- auto Preprocessed = DirectiveStructure.stripDirectives(OrigStream);
-
- auto ParseableStream = cook(Preprocessed, genericLangOpts());
- pairBrackets(ParseableStream);
-
std::vector<FoldingRange> Result;
auto AddFoldingRange = [&](Position Start, Position End,
llvm::StringLiteral Kind) {
@@ -220,7 +213,32 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
auto EndPosition = [&](const Token &T) {
return offsetToPosition(Code, EndOffset(T));
};
+
+ // Preprocessor directives
+ auto PPRanges = pairDirectiveRanges(DirectiveStructure, OrigStream);
+ for (const auto &R : PPRanges) {
+ auto BTok = OrigStream.tokens()[R.Begin];
+ auto ETok = OrigStream.tokens()[R.End];
+ if (ETok.Kind == tok::eof)
+ continue;
+ if (BTok.Line >= ETok.Line)
+ continue;
+
+ Position Start = EndPosition(BTok);
+ Position End = StartPosition(ETok);
+ if (LineFoldingOnly)
+ End.line--;
+ AddFoldingRange(Start, End, FoldingRange::REGION_KIND);
+ }
+
+ // FIXME: Provide ranges in the disabled-PP regions as well.
+ auto Preprocessed = DirectiveStructure.stripDirectives(OrigStream);
+
+ auto ParseableStream = cook(Preprocessed, genericLangOpts());
+ pairBrackets(ParseableStream);
+
auto Tokens = ParseableStream.tokens();
+
// Brackets.
for (const auto &Tok : Tokens) {
if (auto *Paired = Tok.pair()) {
@@ -240,6 +258,7 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
return OriginalToken(T).Length >= 2 &&
Code.substr(StartOffset(T), 2) == "/*";
};
+
// Multi-line comments.
for (auto *T = Tokens.begin(); T != Tokens.end();) {
if (T->Kind != tok::comment) {
diff --git a/clang-tools-extra/clangd/SymbolDocumentation.cpp b/clang-tools-extra/clangd/SymbolDocumentation.cpp
new file mode 100644
index 0000000..9ae1ef3
--- /dev/null
+++ b/clang-tools-extra/clangd/SymbolDocumentation.cpp
@@ -0,0 +1,386 @@
+//===--- SymbolDocumentation.cpp ==-------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolDocumentation.h"
+
+#include "support/Markup.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+std::string commandMarkerAsString(comments::CommandMarkerKind CommandMarker) {
+ switch (CommandMarker) {
+ case comments::CommandMarkerKind::CMK_At:
+ return "@";
+ case comments::CommandMarkerKind::CMK_Backslash:
+ return "\\";
+ }
+ llvm_unreachable("Unknown command marker kind");
+}
+
+void commandToMarkup(markup::Paragraph &Out, StringRef Command,
+ comments::CommandMarkerKind CommandMarker,
+ StringRef Args) {
+ Out.appendBoldText(commandMarkerAsString(CommandMarker) + Command.str());
+ Out.appendSpace();
+ if (!Args.empty()) {
+ Out.appendEmphasizedText(Args.str());
+ }
+}
+} // namespace
+
+class ParagraphToMarkupDocument
+ : public comments::ConstCommentVisitor<ParagraphToMarkupDocument> {
+public:
+ ParagraphToMarkupDocument(markup::Paragraph &Out,
+ const comments::CommandTraits &Traits)
+ : Out(Out), Traits(Traits) {}
+
+ void visitParagraphComment(const comments::ParagraphComment *C) {
+ if (!C)
+ return;
+
+ for (const auto *Child = C->child_begin(); Child != C->child_end();
+ ++Child) {
+ visit(*Child);
+ }
+ }
+
+ void visitTextComment(const comments::TextComment *C) {
+ // Always trim leading space after a newline.
+ StringRef Text = C->getText();
+ if (LastChunkEndsWithNewline && C->getText().starts_with(' '))
+ Text = Text.drop_front();
+
+ LastChunkEndsWithNewline = C->hasTrailingNewline();
+ Out.appendText(Text.str() + (LastChunkEndsWithNewline ? "\n" : ""));
+ }
+
+ void visitInlineCommandComment(const comments::InlineCommandComment *C) {
+
+ if (C->getNumArgs() > 0) {
+ std::string ArgText;
+ for (unsigned I = 0; I < C->getNumArgs(); ++I) {
+ if (!ArgText.empty())
+ ArgText += " ";
+ ArgText += C->getArgText(I);
+ }
+
+ switch (C->getRenderKind()) {
+ case comments::InlineCommandRenderKind::Monospaced:
+ Out.appendCode(ArgText);
+ break;
+ case comments::InlineCommandRenderKind::Bold:
+ Out.appendBoldText(ArgText);
+ break;
+ case comments::InlineCommandRenderKind::Emphasized:
+ Out.appendEmphasizedText(ArgText);
+ break;
+ default:
+ commandToMarkup(Out, C->getCommandName(Traits), C->getCommandMarker(),
+ ArgText);
+ break;
+ }
+ } else {
+ if (C->getCommandName(Traits) == "n") {
+ // \n is a special case, it is used to create a new line.
+ Out.appendText(" \n");
+ LastChunkEndsWithNewline = true;
+ return;
+ }
+
+ commandToMarkup(Out, C->getCommandName(Traits), C->getCommandMarker(),
+ "");
+ }
+ }
+
+ void visitHTMLStartTagComment(const comments::HTMLStartTagComment *STC) {
+ std::string TagText = "<" + STC->getTagName().str();
+
+ for (unsigned I = 0; I < STC->getNumAttrs(); ++I) {
+ const comments::HTMLStartTagComment::Attribute &Attr = STC->getAttr(I);
+ TagText += " " + Attr.Name.str() + "=\"" + Attr.Value.str() + "\"";
+ }
+
+ if (STC->isSelfClosing())
+ TagText += " /";
+ TagText += ">";
+
+ LastChunkEndsWithNewline = STC->hasTrailingNewline();
+ Out.appendText(TagText + (LastChunkEndsWithNewline ? "\n" : ""));
+ }
+
+ void visitHTMLEndTagComment(const comments::HTMLEndTagComment *ETC) {
+ LastChunkEndsWithNewline = ETC->hasTrailingNewline();
+ Out.appendText("</" + ETC->getTagName().str() + ">" +
+ (LastChunkEndsWithNewline ? "\n" : ""));
+ }
+
+private:
+ markup::Paragraph &Out;
+ const comments::CommandTraits &Traits;
+
+ /// If true, the next leading space after a new line is trimmed.
+ /// Initially set it to true, to always trim the first text line.
+ bool LastChunkEndsWithNewline = true;
+};
+
+class ParagraphToString
+ : public comments::ConstCommentVisitor<ParagraphToString> {
+public:
+ ParagraphToString(llvm::raw_string_ostream &Out,
+ const comments::CommandTraits &Traits)
+ : Out(Out), Traits(Traits) {}
+
+ void visitParagraphComment(const comments::ParagraphComment *C) {
+ if (!C)
+ return;
+
+ for (const auto *Child = C->child_begin(); Child != C->child_end();
+ ++Child) {
+ visit(*Child);
+ }
+ }
+
+ void visitTextComment(const comments::TextComment *C) { Out << C->getText(); }
+
+ void visitInlineCommandComment(const comments::InlineCommandComment *C) {
+ Out << commandMarkerAsString(C->getCommandMarker());
+ Out << C->getCommandName(Traits);
+ if (C->getNumArgs() > 0) {
+ for (unsigned I = 0; I < C->getNumArgs(); ++I)
+ Out << " " << C->getArgText(I);
+ }
+ Out << " ";
+ }
+
+ void visitHTMLStartTagComment(const comments::HTMLStartTagComment *STC) {
+ Out << "<" << STC->getTagName().str();
+
+ for (unsigned I = 0; I < STC->getNumAttrs(); ++I) {
+ const comments::HTMLStartTagComment::Attribute &Attr = STC->getAttr(I);
+ Out << " " << Attr.Name.str();
+ if (!Attr.Value.str().empty())
+ Out << "=\"" << Attr.Value.str() << "\"";
+ }
+
+ if (STC->isSelfClosing())
+ Out << " /";
+ Out << ">";
+
+ Out << (STC->hasTrailingNewline() ? "\n" : "");
+ }
+
+ void visitHTMLEndTagComment(const comments::HTMLEndTagComment *ETC) {
+ Out << "</" << ETC->getTagName().str() << ">"
+ << (ETC->hasTrailingNewline() ? "\n" : "");
+ }
+
+private:
+ llvm::raw_string_ostream &Out;
+ const comments::CommandTraits &Traits;
+};
+
+class BlockCommentToMarkupDocument
+ : public comments::ConstCommentVisitor<BlockCommentToMarkupDocument> {
+public:
+ BlockCommentToMarkupDocument(markup::Document &Out,
+ const comments::CommandTraits &Traits)
+ : Out(Out), Traits(Traits) {}
+
+ void visitBlockCommandComment(const comments::BlockCommandComment *B) {
+
+ switch (B->getCommandID()) {
+ case comments::CommandTraits::KCI_arg:
+ case comments::CommandTraits::KCI_li:
+ // \li and \arg are special cases, they are used to create a list item.
+ // In markdown it is a bullet list.
+ ParagraphToMarkupDocument(Out.addBulletList().addItem().addParagraph(),
+ Traits)
+ .visit(B->getParagraph());
+ break;
+ default: {
+ // Some commands have arguments, like \throws.
+ // The arguments are not part of the paragraph.
+ // We need reconstruct them here.
+ std::string ArgText;
+ for (unsigned I = 0; I < B->getNumArgs(); ++I) {
+ if (!ArgText.empty())
+ ArgText += " ";
+ ArgText += B->getArgText(I);
+ }
+ auto &P = Out.addParagraph();
+ commandToMarkup(P, B->getCommandName(Traits), B->getCommandMarker(),
+ ArgText);
+ if (B->getParagraph() && !B->getParagraph()->isWhitespace()) {
+ // For commands with arguments, the paragraph starts after the first
+ // space. Therefore we need to append a space manually in this case.
+ if (!ArgText.empty())
+ P.appendSpace();
+ ParagraphToMarkupDocument(P, Traits).visit(B->getParagraph());
+ }
+ }
+ }
+ }
+
+ void visitVerbatimBlockComment(const comments::VerbatimBlockComment *VB) {
+ commandToMarkup(Out.addParagraph(), VB->getCommandName(Traits),
+ VB->getCommandMarker(), "");
+
+ std::string VerbatimText;
+
+ for (const auto *LI = VB->child_begin(); LI != VB->child_end(); ++LI) {
+ if (const auto *Line = cast<comments::VerbatimBlockLineComment>(*LI)) {
+ VerbatimText += Line->getText().str() + "\n";
+ }
+ }
+
+ Out.addCodeBlock(VerbatimText, "");
+
+ commandToMarkup(Out.addParagraph(), VB->getCloseName(),
+ VB->getCommandMarker(), "");
+ }
+
+ void visitVerbatimLineComment(const comments::VerbatimLineComment *VL) {
+ auto &P = Out.addParagraph();
+ commandToMarkup(P, VL->getCommandName(Traits), VL->getCommandMarker(), "");
+ P.appendSpace().appendCode(VL->getText().str(), true).appendSpace();
+ }
+
+private:
+ markup::Document &Out;
+ const comments::CommandTraits &Traits;
+ StringRef CommentEscapeMarker;
+};
+
+void SymbolDocCommentVisitor::visitBlockCommandComment(
+ const comments::BlockCommandComment *B) {
+ switch (B->getCommandID()) {
+ case comments::CommandTraits::KCI_brief: {
+ if (!BriefParagraph) {
+ BriefParagraph = B->getParagraph();
+ return;
+ }
+ break;
+ }
+ case comments::CommandTraits::KCI_return:
+ case comments::CommandTraits::KCI_returns:
+ if (!ReturnParagraph) {
+ ReturnParagraph = B->getParagraph();
+ return;
+ }
+ break;
+ case comments::CommandTraits::KCI_retval:
+ RetvalParagraphs.push_back(B->getParagraph());
+ return;
+ case comments::CommandTraits::KCI_warning:
+ WarningParagraphs.push_back(B->getParagraph());
+ return;
+ case comments::CommandTraits::KCI_note:
+ NoteParagraphs.push_back(B->getParagraph());
+ return;
+ default:
+ break;
+ }
+
+ // For all other commands, we store them in the UnhandledCommands map.
+ // This allows us to keep the order of the comments.
+ UnhandledCommands[CommentPartIndex] = B;
+ CommentPartIndex++;
+}
+
+void SymbolDocCommentVisitor::paragraphsToMarkup(
+ markup::Document &Out,
+ const llvm::SmallVectorImpl<const comments::ParagraphComment *> &Paragraphs)
+ const {
+ if (Paragraphs.empty())
+ return;
+
+ for (const auto *P : Paragraphs) {
+ ParagraphToMarkupDocument(Out.addParagraph(), Traits).visit(P);
+ }
+}
+
+void SymbolDocCommentVisitor::briefToMarkup(markup::Paragraph &Out) const {
+ if (!BriefParagraph)
+ return;
+ ParagraphToMarkupDocument(Out, Traits).visit(BriefParagraph);
+}
+
+void SymbolDocCommentVisitor::returnToMarkup(markup::Paragraph &Out) const {
+ if (!ReturnParagraph)
+ return;
+ ParagraphToMarkupDocument(Out, Traits).visit(ReturnParagraph);
+}
+
+void SymbolDocCommentVisitor::notesToMarkup(markup::Document &Out) const {
+ paragraphsToMarkup(Out, NoteParagraphs);
+}
+
+void SymbolDocCommentVisitor::warningsToMarkup(markup::Document &Out) const {
+ paragraphsToMarkup(Out, WarningParagraphs);
+}
+
+void SymbolDocCommentVisitor::parameterDocToMarkup(
+ StringRef ParamName, markup::Paragraph &Out) const {
+ if (ParamName.empty())
+ return;
+
+ if (const auto *P = Parameters.lookup(ParamName)) {
+ ParagraphToMarkupDocument(Out, Traits).visit(P->getParagraph());
+ }
+}
+
+void SymbolDocCommentVisitor::parameterDocToString(
+ StringRef ParamName, llvm::raw_string_ostream &Out) const {
+ if (ParamName.empty())
+ return;
+
+ if (const auto *P = Parameters.lookup(ParamName)) {
+ ParagraphToString(Out, Traits).visit(P->getParagraph());
+ }
+}
+
+void SymbolDocCommentVisitor::docToMarkup(markup::Document &Out) const {
+ for (unsigned I = 0; I < CommentPartIndex; ++I) {
+ if (const auto *BC = UnhandledCommands.lookup(I)) {
+ BlockCommentToMarkupDocument(Out, Traits).visit(BC);
+ } else if (const auto *P = FreeParagraphs.lookup(I)) {
+ ParagraphToMarkupDocument(Out.addParagraph(), Traits).visit(P);
+ }
+ }
+}
+
+void SymbolDocCommentVisitor::templateTypeParmDocToMarkup(
+ StringRef TemplateParamName, markup::Paragraph &Out) const {
+ if (TemplateParamName.empty())
+ return;
+
+ if (const auto *TP = TemplateParameters.lookup(TemplateParamName)) {
+ ParagraphToMarkupDocument(Out, Traits).visit(TP->getParagraph());
+ }
+}
+
+void SymbolDocCommentVisitor::templateTypeParmDocToString(
+ StringRef TemplateParamName, llvm::raw_string_ostream &Out) const {
+ if (TemplateParamName.empty())
+ return;
+
+ if (const auto *P = TemplateParameters.lookup(TemplateParamName)) {
+ ParagraphToString(Out, Traits).visit(P->getParagraph());
+ }
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/clang-tools-extra/clangd/SymbolDocumentation.h b/clang-tools-extra/clangd/SymbolDocumentation.h
new file mode 100644
index 0000000..b0d3428
--- /dev/null
+++ b/clang-tools-extra/clangd/SymbolDocumentation.h
@@ -0,0 +1,211 @@
+//===--- SymbolDocumentation.h ==---------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Class to parse doxygen comments into a flat structure for consumption
+// in e.g. Hover and Code Completion
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H
+
+#include "support/Markup.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/CommentLexer.h"
+#include "clang/AST/CommentParser.h"
+#include "clang/AST/CommentSema.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+namespace clang {
+namespace clangd {
+
+class SymbolDocCommentVisitor
+ : public comments::ConstCommentVisitor<SymbolDocCommentVisitor> {
+public:
+ SymbolDocCommentVisitor(comments::FullComment *FC,
+ const CommentOptions &CommentOpts)
+ : Traits(Allocator, CommentOpts), Allocator() {
+ if (!FC)
+ return;
+
+ for (auto *Block : FC->getBlocks()) {
+ visit(Block);
+ }
+ }
+
+ SymbolDocCommentVisitor(llvm::StringRef Documentation,
+ const CommentOptions &CommentOpts)
+ : Traits(Allocator, CommentOpts), Allocator() {
+
+ if (Documentation.empty())
+ return;
+
+ CommentWithMarkers.reserve(Documentation.size() +
+ Documentation.count('\n') * 3);
+
+ // The comment lexer expects doxygen markers, so add them back.
+ // We need to use the /// style doxygen markers because the comment could
+ // contain the closing the closing tag "*/" of a C Style "/** */" comment
+ // which would break the parsing if we would just enclose the comment text
+ // with "/** */".
+ CommentWithMarkers = "///";
+ bool NewLine = true;
+ for (char C : Documentation) {
+ if (C == '\n') {
+ CommentWithMarkers += "\n///";
+ NewLine = true;
+ } else {
+ if (NewLine && (C == '<')) {
+ // A comment line starting with '///<' is treated as a doxygen
+ // comment. Therefore add a space to separate the '<' from the comment
+ // marker. This allows to parse html tags at the beginning of a line
+ // and the escape marker prevents adding the artificial space in the
+ // markup documentation. The extra space will not be rendered, since
+ // we render it as markdown.
+ CommentWithMarkers += ' ';
+ }
+ CommentWithMarkers += C;
+ NewLine = false;
+ }
+ }
+ SourceManagerForFile SourceMgrForFile("mock_file.cpp", CommentWithMarkers);
+
+ SourceManager &SourceMgr = SourceMgrForFile.get();
+ // The doxygen Sema requires a Diagostics consumer, since it reports
+ // warnings e.g. when parameters are not documented correctly. These
+ // warnings are not relevant for us, so we can ignore them.
+ SourceMgr.getDiagnostics().setClient(new IgnoringDiagConsumer);
+
+ comments::Sema S(Allocator, SourceMgr, SourceMgr.getDiagnostics(), Traits,
+ /*PP=*/nullptr);
+ comments::Lexer L(Allocator, SourceMgr.getDiagnostics(), Traits,
+ SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()),
+ CommentWithMarkers.data(),
+ CommentWithMarkers.data() + CommentWithMarkers.size());
+ comments::Parser P(L, S, Allocator, SourceMgr, SourceMgr.getDiagnostics(),
+ Traits);
+ comments::FullComment *FC = P.parseFullComment();
+
+ if (!FC)
+ return;
+
+ for (auto *Block : FC->getBlocks()) {
+ visit(Block);
+ }
+ }
+
+ bool isParameterDocumented(StringRef ParamName) const {
+ return Parameters.contains(ParamName);
+ }
+
+ bool isTemplateTypeParmDocumented(StringRef ParamName) const {
+ return TemplateParameters.contains(ParamName);
+ }
+
+ bool hasBriefCommand() const { return BriefParagraph; }
+
+ bool hasReturnCommand() const { return ReturnParagraph; }
+
+ bool hasRetvalCommands() const { return !RetvalParagraphs.empty(); }
+
+ bool hasNoteCommands() const { return !NoteParagraphs.empty(); }
+
+ bool hasWarningCommands() const { return !WarningParagraphs.empty(); }
+
+ /// Converts all unhandled comment commands to a markup document.
+ void docToMarkup(markup::Document &Out) const;
+ /// Converts the "brief" command(s) to a markup document.
+ void briefToMarkup(markup::Paragraph &Out) const;
+ /// Converts the "return" command(s) to a markup document.
+ void returnToMarkup(markup::Paragraph &Out) const;
+ /// Converts the "note" command(s) to a markup document.
+ void notesToMarkup(markup::Document &Out) const;
+ /// Converts the "warning" command(s) to a markup document.
+ void warningsToMarkup(markup::Document &Out) const;
+
+ void visitBlockCommandComment(const comments::BlockCommandComment *B);
+
+ void templateTypeParmDocToMarkup(StringRef TemplateParamName,
+ markup::Paragraph &Out) const;
+
+ void templateTypeParmDocToString(StringRef TemplateParamName,
+ llvm::raw_string_ostream &Out) const;
+
+ void parameterDocToMarkup(StringRef ParamName, markup::Paragraph &Out) const;
+
+ void parameterDocToString(StringRef ParamName,
+ llvm::raw_string_ostream &Out) const;
+
+ void visitParagraphComment(const comments::ParagraphComment *P) {
+ FreeParagraphs[CommentPartIndex] = P;
+ CommentPartIndex++;
+ }
+
+ void visitParamCommandComment(const comments::ParamCommandComment *P) {
+ Parameters[P->getParamNameAsWritten()] = P;
+ }
+
+ void visitTParamCommandComment(const comments::TParamCommandComment *TP) {
+ TemplateParameters[TP->getParamNameAsWritten()] = std::move(TP);
+ }
+
+private:
+ comments::CommandTraits Traits;
+ llvm::BumpPtrAllocator Allocator;
+ std::string CommentWithMarkers;
+
+ /// Index to keep track of the order of the comments.
+ /// We want to rearange some commands like \\param.
+ /// This index allows us to keep the order of the other comment parts.
+ unsigned CommentPartIndex = 0;
+
+ /// Paragraph of the "brief" command.
+ const comments::ParagraphComment *BriefParagraph = nullptr;
+
+ /// Paragraph of the "return" command.
+ const comments::ParagraphComment *ReturnParagraph = nullptr;
+
+ /// Paragraph(s) of the "note" command(s)
+ llvm::SmallVector<const comments::ParagraphComment *> RetvalParagraphs;
+
+ /// Paragraph(s) of the "note" command(s)
+ llvm::SmallVector<const comments::ParagraphComment *> NoteParagraphs;
+
+ /// Paragraph(s) of the "warning" command(s)
+ llvm::SmallVector<const comments::ParagraphComment *> WarningParagraphs;
+
+ /// All the paragraphs we don't have any special handling for,
+ /// e.g. "details".
+ llvm::SmallDenseMap<unsigned, const comments::BlockCommandComment *>
+ UnhandledCommands;
+
+ /// Parsed paragaph(s) of the "param" comamnd(s)
+ llvm::SmallDenseMap<StringRef, const comments::ParamCommandComment *>
+ Parameters;
+
+ /// Parsed paragaph(s) of the "tparam" comamnd(s)
+ llvm::SmallDenseMap<StringRef, const comments::TParamCommandComment *>
+ TemplateParameters;
+
+ /// All "free" text paragraphs.
+ llvm::SmallDenseMap<unsigned, const comments::ParagraphComment *>
+ FreeParagraphs;
+
+ void paragraphsToMarkup(
+ markup::Document &Out,
+ const llvm::SmallVectorImpl<const comments::ParagraphComment *>
+ &Paragraphs) const;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index 83a8b72..a253a63 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -1876,7 +1876,7 @@ static void fillSubTypes(const SymbolID &ID,
});
}
-using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
+using RecursionProtectionSet = llvm::SmallPtrSet<const CXXRecordDecl *, 4>;
// Extracts parents from AST and populates the type hierarchy item.
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,
@@ -1965,7 +1965,8 @@ std::vector<const CXXRecordDecl *> findRecordTypeAt(ParsedAST &AST,
// Return the type most associated with an AST node.
// This isn't precisely defined: we want "go to type" to do something useful.
-static QualType typeForNode(const SelectionTree::Node *N) {
+static QualType typeForNode(const ASTContext &Ctx,
+ const SelectionTree::Node *N) {
// If we're looking at a namespace qualifier, walk up to what it's qualifying.
// (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
while (N && N->ASTNode.get<NestedNameSpecifierLoc>())
@@ -1999,10 +2000,13 @@ static QualType typeForNode(const SelectionTree::Node *N) {
if (const Decl *D = N->ASTNode.get<Decl>()) {
struct Visitor : ConstDeclVisitor<Visitor, QualType> {
+ const ASTContext &Ctx;
+ Visitor(const ASTContext &Ctx) : Ctx(Ctx) {}
+
QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); }
// Declaration of a type => that type.
QualType VisitTypeDecl(const TypeDecl *D) {
- return QualType(D->getTypeForDecl(), 0);
+ return Ctx.getTypeDeclType(D);
}
// Exception: alias declaration => the underlying type, not the alias.
QualType VisitTypedefNameDecl(const TypedefNameDecl *D) {
@@ -2012,7 +2016,7 @@ static QualType typeForNode(const SelectionTree::Node *N) {
QualType VisitTemplateDecl(const TemplateDecl *D) {
return Visit(D->getTemplatedDecl());
}
- } V;
+ } V(Ctx);
return V.Visit(D);
}
@@ -2156,7 +2160,8 @@ std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos,
// unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some
// information about the type you may have not known before
// (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).
- for (const QualType& Type : unwrapFindType(typeForNode(N), AST.getHeuristicResolver()))
+ for (const QualType &Type : unwrapFindType(
+ typeForNode(AST.getASTContext(), N), AST.getHeuristicResolver()))
llvm::copy(locateSymbolForType(AST, Type, Index),
std::back_inserter(LocatedSymbols));
diff --git a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp
index 67fc451..f65c74f 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp
@@ -115,13 +115,6 @@ private:
const SourceManager &SM;
};
-bool isFullyQualified(const NestedNameSpecifier *NNS) {
- if (!NNS)
- return false;
- return NNS->getKind() == NestedNameSpecifier::Global ||
- isFullyQualified(NNS->getPrefix());
-}
-
struct InsertionPointData {
// Location to insert the "using" statement. If invalid then the statement
// should not be inserted at all (it already exists).
@@ -167,18 +160,20 @@ findInsertionPoint(const Tweak::Selection &Inputs,
for (auto &U : Usings) {
// Only "upgrade" to fully qualified is all relevant using decls are fully
// qualified. Otherwise trust what the user typed.
- if (!isFullyQualified(U->getQualifier()))
+ if (!U->getQualifier().isFullyQualified())
AlwaysFullyQualify = false;
if (SM.isBeforeInTranslationUnit(Inputs.Cursor, U->getUsingLoc()))
// "Usings" is sorted, so we're done.
break;
- if (const auto *Namespace = dyn_cast_if_present<NamespaceDecl>(
- U->getQualifier()->getAsNamespace())) {
+ if (NestedNameSpecifier Qualifier = U->getQualifier();
+ Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) {
+ const auto *Namespace =
+ U->getQualifier().getAsNamespaceAndPrefix().Namespace;
if (Namespace->getCanonicalDecl() ==
QualifierToRemove.getNestedNameSpecifier()
- ->getAsNamespace()
- ->getCanonicalDecl() &&
+ .getAsNamespaceAndPrefix()
+ .Namespace->getCanonicalDecl() &&
U->getName() == Name) {
return InsertionPointData();
}
@@ -232,8 +227,9 @@ findInsertionPoint(const Tweak::Selection &Inputs,
}
bool isNamespaceForbidden(const Tweak::Selection &Inputs,
- const NestedNameSpecifier &Namespace) {
- const auto *NS = dyn_cast<NamespaceDecl>(Namespace.getAsNamespace());
+ NestedNameSpecifier Namespace) {
+ const auto *NS =
+ dyn_cast<NamespaceDecl>(Namespace.getAsNamespaceAndPrefix().Namespace);
if (!NS)
return true;
std::string NamespaceStr = printNamespaceScope(*NS);
@@ -247,11 +243,11 @@ bool isNamespaceForbidden(const Tweak::Selection &Inputs,
return false;
}
-std::string getNNSLAsString(NestedNameSpecifierLoc &NNSL,
+std::string getNNSLAsString(NestedNameSpecifierLoc NNSL,
const PrintingPolicy &Policy) {
std::string Out;
llvm::raw_string_ostream OutStream(Out);
- NNSL.getNestedNameSpecifier()->print(OutStream, Policy);
+ NNSL.getNestedNameSpecifier().print(OutStream, Policy);
return OutStream.str();
}
@@ -276,16 +272,15 @@ bool AddUsing::prepare(const Selection &Inputs) {
continue;
}
if (auto *T = Node->ASTNode.get<TypeLoc>()) {
- if (T->getAs<ElaboratedTypeLoc>()) {
+ // Find the outermost TypeLoc.
+ if (Node->Parent->ASTNode.get<NestedNameSpecifierLoc>())
+ continue;
+ if (isa<TagType, TemplateSpecializationType, TypedefType, UsingType,
+ UnresolvedUsingType>(T->getTypePtr()))
break;
- }
- if (Node->Parent->ASTNode.get<TypeLoc>() ||
- Node->Parent->ASTNode.get<NestedNameSpecifierLoc>()) {
- // Node is TypeLoc, but it's parent is either TypeLoc or
- // NestedNameSpecifier. In both cases, we want to go up, to find
- // the outermost TypeLoc.
+ // Find the outermost TypeLoc.
+ if (Node->Parent->ASTNode.get<TypeLoc>())
continue;
- }
}
break;
}
@@ -307,32 +302,70 @@ bool AddUsing::prepare(const Selection &Inputs) {
MustInsertAfterLoc = D->getDecl()->getBeginLoc();
}
} else if (auto *T = Node->ASTNode.get<TypeLoc>()) {
- if (auto E = T->getAs<ElaboratedTypeLoc>()) {
- QualifierToRemove = E.getQualifierLoc();
-
- SpelledNameRange = E.getSourceRange();
- if (auto T = E.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
- // Remove the template arguments from the name.
- SpelledNameRange.setEnd(T.getLAngleLoc().getLocWithOffset(-1));
- }
-
- if (const auto *ET = E.getTypePtr()) {
- if (const auto *TDT =
- dyn_cast<TypedefType>(ET->getNamedType().getTypePtr())) {
- MustInsertAfterLoc = TDT->getDecl()->getBeginLoc();
- } else if (auto *TD = ET->getAsTagDecl()) {
- MustInsertAfterLoc = TD->getBeginLoc();
- }
- }
+ switch (T->getTypeLocClass()) {
+ case TypeLoc::TemplateSpecialization: {
+ auto TL = T->castAs<TemplateSpecializationTypeLoc>();
+ QualifierToRemove = TL.getQualifierLoc();
+ if (!QualifierToRemove)
+ break;
+ SpelledNameRange = TL.getTemplateNameLoc();
+ if (auto *TD = TL.getTypePtr()->getTemplateName().getAsTemplateDecl(
+ /*IgnoreDeduced=*/true))
+ MustInsertAfterLoc = TD->getBeginLoc();
+ break;
+ }
+ case TypeLoc::Enum:
+ case TypeLoc::Record:
+ case TypeLoc::InjectedClassName: {
+ auto TL = T->castAs<TagTypeLoc>();
+ QualifierToRemove = TL.getQualifierLoc();
+ if (!QualifierToRemove)
+ break;
+ SpelledNameRange = TL.getNameLoc();
+ MustInsertAfterLoc = TL.getOriginalDecl()->getBeginLoc();
+ break;
+ }
+ case TypeLoc::Typedef: {
+ auto TL = T->castAs<TypedefTypeLoc>();
+ QualifierToRemove = TL.getQualifierLoc();
+ if (!QualifierToRemove)
+ break;
+ SpelledNameRange = TL.getNameLoc();
+ MustInsertAfterLoc = TL.getDecl()->getBeginLoc();
+ break;
+ }
+ case TypeLoc::UnresolvedUsing: {
+ auto TL = T->castAs<UnresolvedUsingTypeLoc>();
+ QualifierToRemove = TL.getQualifierLoc();
+ if (!QualifierToRemove)
+ break;
+ SpelledNameRange = TL.getNameLoc();
+ MustInsertAfterLoc = TL.getDecl()->getBeginLoc();
+ break;
+ }
+ case TypeLoc::Using: {
+ auto TL = T->castAs<UsingTypeLoc>();
+ QualifierToRemove = TL.getQualifierLoc();
+ if (!QualifierToRemove)
+ break;
+ SpelledNameRange = TL.getNameLoc();
+ MustInsertAfterLoc = TL.getDecl()->getBeginLoc();
+ break;
+ }
+ default:
+ break;
}
+ if (QualifierToRemove)
+ SpelledNameRange.setBegin(QualifierToRemove.getBeginLoc());
}
if (!QualifierToRemove ||
// FIXME: This only supports removing qualifiers that are made up of just
// namespace names. If qualifier contains a type, we could take the
// longest namespace prefix and remove that.
- !QualifierToRemove.getNestedNameSpecifier()->getAsNamespace() ||
+ QualifierToRemove.getNestedNameSpecifier().getKind() !=
+ NestedNameSpecifier::Kind::Namespace ||
// Respect user config.
- isNamespaceForbidden(Inputs, *QualifierToRemove.getNestedNameSpecifier()))
+ isNamespaceForbidden(Inputs, QualifierToRemove.getNestedNameSpecifier()))
return false;
// Macros are difficult. We only want to offer code action when what's spelled
// under the cursor is a namespace qualifier. If it's a macro that expands to
@@ -384,7 +417,7 @@ Expected<Tweak::Effect> AddUsing::apply(const Selection &Inputs) {
llvm::raw_string_ostream UsingTextStream(UsingText);
UsingTextStream << "using ";
if (InsertionPoint->AlwaysFullyQualify &&
- !isFullyQualified(QualifierToRemove.getNestedNameSpecifier()))
+ !QualifierToRemove.getNestedNameSpecifier().isFullyQualified())
UsingTextStream << "::";
UsingTextStream << QualifierToSpell << SpelledName << ";"
<< InsertionPoint->Suffix;
diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp
index cd07cbf..bc9a790 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp
@@ -181,7 +181,7 @@ struct ExtractionZone {
bool requiresHoisting(const SourceManager &SM,
const HeuristicResolver *Resolver) const {
// First find all the declarations that happened inside extraction zone.
- llvm::SmallSet<const Decl *, 1> DeclsInExtZone;
+ llvm::SmallPtrSet<const Decl *, 1> DeclsInExtZone;
for (auto *RootStmt : RootStmts) {
findExplicitReferences(
RootStmt,
@@ -362,7 +362,7 @@ struct NewFunction {
SourceLocation DefinitionPoint;
std::optional<SourceLocation> ForwardDeclarationPoint;
const CXXRecordDecl *EnclosingClass = nullptr;
- const NestedNameSpecifier *DefinitionQualifier = nullptr;
+ NestedNameSpecifier DefinitionQualifier = std::nullopt;
const DeclContext *SemanticDC = nullptr;
const DeclContext *SyntacticDC = nullptr;
const DeclContext *ForwardDeclarationSyntacticDC = nullptr;
@@ -455,13 +455,12 @@ std::string NewFunction::renderQualifiers() const {
}
std::string NewFunction::renderDeclarationName(FunctionDeclKind K) const {
- if (DefinitionQualifier == nullptr || K != OutOfLineDefinition) {
+ if (!DefinitionQualifier || K != OutOfLineDefinition)
return Name;
- }
std::string QualifierName;
llvm::raw_string_ostream Oss(QualifierName);
- DefinitionQualifier->print(Oss, *LangOpts);
+ DefinitionQualifier.print(Oss, *LangOpts);
return llvm::formatv("{0}{1}", QualifierName, Name);
}
diff --git a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
index 43cfc76..2c98417 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
@@ -113,11 +113,11 @@ bool PopulateSwitch::prepare(const Selection &Sel) {
// Ignore implicit casts, since enums implicitly cast to integer types.
Cond = Cond->IgnoreParenImpCasts();
// Get the canonical type to handle typedefs.
- EnumT = Cond->getType().getCanonicalType()->getAsAdjusted<EnumType>();
+ EnumT = Cond->getType()->getAsCanonical<EnumType>();
if (!EnumT)
return false;
- EnumD = EnumT->getDecl();
- if (!EnumD || EnumD->isDependentType())
+ EnumD = EnumT->getOriginalDecl()->getDefinitionOrSelf();
+ if (EnumD->isDependentType())
return false;
// Finally, check which cases exist and which are covered.
diff --git a/clang-tools-extra/clangd/support/DirectiveTree.cpp b/clang-tools-extra/clangd/support/DirectiveTree.cpp
index 7ea08ad..97b0598 100644
--- a/clang-tools-extra/clangd/support/DirectiveTree.cpp
+++ b/clang-tools-extra/clangd/support/DirectiveTree.cpp
@@ -356,5 +356,62 @@ TokenStream DirectiveTree::stripDirectives(const TokenStream &In) const {
return Out;
}
+namespace {
+class RangePairer {
+ std::vector<Token::Range> &Ranges;
+
+public:
+ RangePairer(std::vector<Token::Range> &Ranges) : Ranges(Ranges) {}
+
+ void walk(const DirectiveTree &T) {
+ for (const auto &C : T.Chunks)
+ std::visit(*this, C);
+ }
+
+ void operator()(const DirectiveTree::Code &C) {}
+
+ void operator()(const DirectiveTree::Directive &) {}
+
+ void operator()(const DirectiveTree::Conditional &C) {
+ Token::Range Range;
+ Token::Index Last;
+ auto First = true;
+ for (const auto &[Directive, _] : C.Branches) {
+ if (First) {
+ First = false;
+ } else {
+ Range = {Last, Directive.Tokens.Begin};
+ Ranges.push_back(Range);
+ }
+ Last = Directive.Tokens.Begin;
+ }
+
+ if (C.End.Kind != tok::pp_not_keyword) {
+ Range = {Last, C.End.Tokens.Begin};
+ Ranges.push_back(Range);
+ }
+
+ for (const auto &[_, SubTree] : C.Branches)
+ walk(SubTree);
+ }
+};
+} // namespace
+
+std::vector<Token::Range> pairDirectiveRanges(const DirectiveTree &Tree,
+ const TokenStream &Code) {
+ std::vector<Token::Range> Ranges;
+ RangePairer(Ranges).walk(Tree);
+
+ // Transform paired ranges to start with last token in its logical line
+ for (auto &R : Ranges) {
+ const Token *Tok = &Code.tokens()[R.Begin + 1];
+ while (Tok->Kind != tok::eof && !Tok->flag(LexFlags::StartsPPLine))
+ ++Tok;
+ Tok = Tok - 1;
+ R.Begin = Tok->OriginalIndex;
+ }
+ return Ranges;
+}
+
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/support/DirectiveTree.h b/clang-tools-extra/clangd/support/DirectiveTree.h
index 34f5a88..373af32 100644
--- a/clang-tools-extra/clangd/support/DirectiveTree.h
+++ b/clang-tools-extra/clangd/support/DirectiveTree.h
@@ -124,6 +124,10 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &,
/// The choices are stored in Conditional::Taken nodes.
void chooseConditionalBranches(DirectiveTree &, const TokenStream &Code);
+/// Pairs preprocessor conditional directives and computes their token ranges.
+std::vector<Token::Range> pairDirectiveRanges(const DirectiveTree &Tree,
+ const TokenStream &Code);
+
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/support/Markup.cpp b/clang-tools-extra/clangd/support/Markup.cpp
index a130830..89bdc65 100644
--- a/clang-tools-extra/clangd/support/Markup.cpp
+++ b/clang-tools-extra/clangd/support/Markup.cpp
@@ -363,7 +363,12 @@ public:
void renderMarkdown(llvm::raw_ostream &OS) const override {
std::string Marker = getMarkerForCodeBlock(Contents);
// No need to pad from previous blocks, as they should end with a new line.
- OS << Marker << Language << '\n' << Contents << '\n' << Marker << '\n';
+ OS << Marker << Language << '\n' << Contents;
+ if (!Contents.empty() && Contents.back() != '\n')
+ OS << '\n';
+ // Always end with an empty line to separate code blocks from following
+ // paragraphs.
+ OS << Marker << "\n\n";
}
void renderPlainText(llvm::raw_ostream &OS) const override {
diff --git a/clang-tools-extra/clangd/test/modules_no_cdb.test b/clang-tools-extra/clangd/test/modules_no_cdb.test
new file mode 100644
index 0000000..8f92be2
--- /dev/null
+++ b/clang-tools-extra/clangd/test/modules_no_cdb.test
@@ -0,0 +1,66 @@
+# A smoke test to check that clangd works without compilation database
+#
+# Windows have different escaping modes.
+# FIXME: We should add one for windows.
+# UNSUPPORTED: system-windows
+#
+# RUN: rm -fr %t
+# RUN: mkdir -p %t
+# RUN: split-file %s %t
+#
+# RUN: sed -e "s|DIR|%/t|g" %t/definition.jsonrpc.tmpl > %t/definition.jsonrpc
+#
+# RUN: clangd -experimental-modules-support -lit-test < %t/definition.jsonrpc \
+# RUN: | FileCheck -strict-whitespace %t/definition.jsonrpc
+
+#--- A.h
+void printA();
+
+#--- Use.cpp
+#include "A.h"
+void foo() {
+ print
+}
+
+#--- definition.jsonrpc.tmpl
+{
+ "jsonrpc": "2.0",
+ "id": 0,
+ "method": "initialize",
+ "params": {
+ "processId": 123,
+ "rootPath": "clangd",
+ "capabilities": {
+ "textDocument": {
+ "completion": {
+ "completionItem": {
+ "snippetSupport": true
+ }
+ }
+ }
+ },
+ "trace": "off"
+ }
+}
+---
+{
+ "jsonrpc": "2.0",
+ "method": "textDocument/didOpen",
+ "params": {
+ "textDocument": {
+ "uri": "file://DIR/Use.cpp",
+ "languageId": "cpp",
+ "version": 1,
+ "text": "#include \"A.h\"\nvoid foo() {\n print\n}\n"
+ }
+ }
+}
+
+# CHECK: "message"{{.*}}printA{{.*}}(fix available)
+
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file://DIR/Use.cpp"},"context":{"triggerKind":1},"position":{"line":2,"character":6}}}
+---
+{"jsonrpc":"2.0","id":2,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp
index d0bc3c4..76d46ba 100644
--- a/clang-tools-extra/clangd/unittests/ASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp
@@ -421,7 +421,7 @@ TEST(ClangdAST, GetQualification) {
{
R"cpp(
namespace ns1 { namespace ns2 { void Foo(); } }
- void insert(); // ns2::Foo
+ void insert(); // ns1::ns2::Foo
namespace ns1 {
void insert(); // ns2::Foo
namespace ns2 {
@@ -429,7 +429,7 @@ TEST(ClangdAST, GetQualification) {
}
}
)cpp",
- {"ns2::", "ns2::", ""},
+ {"ns1::ns2::", "ns2::", ""},
{"ns1::"},
},
{
@@ -531,7 +531,8 @@ TEST(ClangdAST, PrintType) {
ASSERT_EQ(InsertionPoints.size(), Case.Types.size());
for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
const auto *DC = InsertionPoints[I];
- EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC),
+ EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC,
+ /*Placeholder=*/"", /*FullyQualify=*/true),
Case.Types[I]);
}
}
diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt
index d425070..9656eea 100644
--- a/clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -92,6 +92,7 @@ add_unittest(ClangdUnitTests ClangdTests
SourceCodeTests.cpp
StdLibTests.cpp
SymbolCollectorTests.cpp
+ SymbolDocumentationTests.cpp
SymbolInfoTests.cpp
SyncAPI.cpp
TUSchedulerTests.cpp
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 1a1c32c..7640569 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -4473,6 +4473,198 @@ TEST(CompletionTest, SkipExplicitObjectParameter) {
snippetSuffix(""))));
}
}
+
+TEST(CompletionTest, MemberAccessInExplicitObjMemfn) {
+ Annotations Code(R"cpp(
+ struct A {
+ int member {};
+ int memberFnA(int a);
+ int memberFnA(this A&, float a);
+
+ void foo(this A& self) {
+ // Should not offer any members here, since
+ // it needs to be referenced through `self`.
+ mem$c1^;
+ // should offer all results
+ self.mem$c2^;
+
+ [&]() {
+ // should not offer any results
+ mem$c3^;
+ }();
+ }
+ };
+ )cpp");
+
+ auto TU = TestTU::withCode(Code.code());
+ TU.ExtraArgs = {"-std=c++23"};
+
+ auto Preamble = TU.preamble();
+ ASSERT_TRUE(Preamble);
+
+ CodeCompleteOptions Opts{};
+
+ MockFS FS;
+ auto Inputs = TU.inputs(FS);
+
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"),
+ Preamble.get(), Inputs, Opts);
+
+ EXPECT_THAT(Result.Completions, ElementsAre());
+ }
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),
+ Preamble.get(), Inputs, Opts);
+
+ EXPECT_THAT(
+ Result.Completions,
+ UnorderedElementsAre(named("member"),
+ AllOf(named("memberFnA"), signature("(int a)"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("memberFnA"), signature("(float a)"),
+ snippetSuffix("(${1:float a})"))));
+ }
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),
+ Preamble.get(), Inputs, Opts);
+
+ EXPECT_THAT(Result.Completions, ElementsAre());
+ }
+}
+
+TEST(CompletionTest, ListExplicitObjectOverloads) {
+ Annotations Code(R"cpp(
+ struct S {
+ void foo1(int a);
+ void foo2(int a) const;
+ void foo2(this const S& self, float a);
+ void foo3(this const S& self, int a);
+ void foo4(this S& self, int a);
+ };
+
+ void S::foo1(int a) {
+ this->$c1^;
+ }
+
+ void S::foo2(int a) const {
+ this->$c2^;
+ }
+
+ void S::foo3(this const S& self, int a) {
+ self.$c3^;
+ }
+
+ void S::foo4(this S& self, int a) {
+ self.$c4^;
+ }
+
+ void test1(S s) {
+ s.$c5^;
+ }
+
+ void test2(const S s) {
+ s.$c6^;
+ }
+ )cpp");
+
+ auto TU = TestTU::withCode(Code.code());
+ TU.ExtraArgs = {"-std=c++23"};
+
+ auto Preamble = TU.preamble();
+ ASSERT_TRUE(Preamble);
+
+ CodeCompleteOptions Opts{};
+
+ MockFS FS;
+ auto Inputs = TU.inputs(FS);
+
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"),
+ Preamble.get(), Inputs, Opts);
+ EXPECT_THAT(
+ Result.Completions,
+ UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(float a) const"),
+ snippetSuffix("(${1:float a})")),
+ AllOf(named("foo3"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo4"), signature("(int a)"),
+ snippetSuffix("(${1:int a})"))));
+ }
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),
+ Preamble.get(), Inputs, Opts);
+ EXPECT_THAT(
+ Result.Completions,
+ UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(float a) const"),
+ snippetSuffix("(${1:float a})")),
+ AllOf(named("foo3"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})"))));
+ }
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),
+ Preamble.get(), Inputs, Opts);
+ EXPECT_THAT(
+ Result.Completions,
+ UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(float a) const"),
+ snippetSuffix("(${1:float a})")),
+ AllOf(named("foo3"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})"))));
+ }
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c4"),
+ Preamble.get(), Inputs, Opts);
+ EXPECT_THAT(
+ Result.Completions,
+ UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(float a) const"),
+ snippetSuffix("(${1:float a})")),
+ AllOf(named("foo3"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo4"), signature("(int a)"),
+ snippetSuffix("(${1:int a})"))));
+ }
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c5"),
+ Preamble.get(), Inputs, Opts);
+ EXPECT_THAT(
+ Result.Completions,
+ UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(float a) const"),
+ snippetSuffix("(${1:float a})")),
+ AllOf(named("foo3"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo4"), signature("(int a)"),
+ snippetSuffix("(${1:int a})"))));
+ }
+ {
+ auto Result = codeComplete(testPath(TU.Filename), Code.point("c6"),
+ Preamble.get(), Inputs, Opts);
+ EXPECT_THAT(
+ Result.Completions,
+ UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})")),
+ AllOf(named("foo2"), signature("(float a) const"),
+ snippetSuffix("(${1:float a})")),
+ AllOf(named("foo3"), signature("(int a) const"),
+ snippetSuffix("(${1:int a})"))));
+ }
+}
+
} // namespace
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
index d71b8d5..d94e706 100644
--- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
@@ -230,17 +230,19 @@ TEST(ParseYAML, CodePatterns) {
EXPECT_THAT(Results[0].Completion.CodePatterns, llvm::ValueIs(val("None")));
}
-TEST(ParseYAML, ShowAKA) {
+TEST(ParseYAML, Hover) {
CapturedDiags Diags;
Annotations YAML(R"yaml(
Hover:
ShowAKA: True
+ MacroContentsLimit: 4096
)yaml");
auto Results =
Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
ASSERT_THAT(Diags.Diagnostics, IsEmpty());
ASSERT_EQ(Results.size(), 1u);
EXPECT_THAT(Results[0].Hover.ShowAKA, llvm::ValueIs(val(true)));
+ EXPECT_THAT(Results[0].Hover.MacroContentsLimit, llvm::ValueIs(val(4096U)));
}
TEST(ParseYAML, InlayHints) {
diff --git a/clang-tools-extra/clangd/unittests/DumpASTTests.cpp b/clang-tools-extra/clangd/unittests/DumpASTTests.cpp
index cb2c17a..5c857d0 100644
--- a/clang-tools-extra/clangd/unittests/DumpASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/DumpASTTests.cpp
@@ -72,15 +72,14 @@ declaration: Namespace - root
expression: BinaryOperator - +
expression: ImplicitCast - LValueToRValue
expression: DeclRef - x
- specifier: TypeSpec
+ specifier: Type
type: Record - S
expression: ImplicitCast - LValueToRValue
expression: Member - x
expression: CXXBindTemporary
expression: CXXTemporaryObject - S
- type: Elaborated
+ type: Record - S
specifier: Namespace - root::
- type: Record - S
)"},
{R"cpp(
namespace root {
@@ -104,14 +103,13 @@ declaration: Namespace - root
expression: BinaryOperator - +
expression: ImplicitCast - LValueToRValue
expression: DeclRef - x
- specifier: TypeSpec
+ specifier: Type
type: Record - S
expression: ImplicitCast - LValueToRValue
expression: Member - x
expression: CXXTemporaryObject - S
- type: Elaborated
+ type: Record - S
specifier: Namespace - root::
- type: Record - S
)"},
{R"cpp(
namespace root {
@@ -138,7 +136,7 @@ declaration: Namespace - root
type: Builtin - unsigned int
statement: Return
expression: DependentScopeDeclRef - value
- specifier: TypeSpec
+ specifier: Type
type: TemplateTypeParm - T
)"},
{R"cpp(
@@ -154,8 +152,7 @@ declaration: Var - root
expression: DeclRef - operator+
expression: MaterializeTemporary - lvalue
expression: CXXTemporaryObject - Foo
- type: Elaborated
- type: Record - Foo
+ type: Record - Foo
expression: IntegerLiteral - 42
)"},
{R"cpp(
diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 4d77f9d..f369e1b 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -731,6 +731,12 @@ TEST_F(TargetDeclTest, BuiltinTemplates) {
using type_pack_element = [[__type_pack_element]]<N, Pack...>;
)cpp";
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
+
+ Code = R"cpp(
+ template <template <class...> class Templ, class... Types>
+ using dedup_types = Templ<[[__builtin_dedup_pack]]<Types...>...>;
+ )cpp";
+ EXPECT_DECLS("TemplateSpecializationTypeLoc", );
}
TEST_F(TargetDeclTest, MemberOfTemplate) {
@@ -992,7 +998,7 @@ TEST_F(TargetDeclTest, DependentTypes) {
)cpp";
EXPECT_DECLS("DependentNameTypeLoc", "struct B");
- // Heuristic resolution of dependent type name which doesn't get a TypeLoc
+ // Heuristic resolution of dependent type name within a NestedNameSpecifierLoc
Code = R"cpp(
template <typename>
struct A { struct B { struct C {}; }; };
@@ -1000,7 +1006,7 @@ TEST_F(TargetDeclTest, DependentTypes) {
template <typename T>
void foo(typename A<T>::[[B]]::C);
)cpp";
- EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
+ EXPECT_DECLS("DependentNameTypeLoc", "struct B");
// Heuristic resolution of dependent type name whose qualifier is also
// dependent
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 12d260d..743c0dc 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2894,7 +2894,7 @@ TEST(Hover, All) {
)cpp",
[](HoverInfo &HI) {
HI.Name = "this";
- HI.Definition = "const Foo<T> *";
+ HI.Definition = "const ns::Foo<T> *";
}},
{
R"cpp(// this expr for specialization class
@@ -2910,7 +2910,7 @@ TEST(Hover, All) {
)cpp",
[](HoverInfo &HI) {
HI.Name = "this";
- HI.Definition = "Foo<int> *";
+ HI.Definition = "ns::Foo<int> *";
}},
{
R"cpp(// this expr for partial specialization struct
@@ -2926,7 +2926,7 @@ TEST(Hover, All) {
)cpp",
[](HoverInfo &HI) {
HI.Name = "this";
- HI.Definition = "const Foo<int, F> *";
+ HI.Definition = "const ns::Foo<int, F> *";
}},
{
R"cpp(
@@ -3046,8 +3046,8 @@ TEST(Hover, All) {
HI.Kind = index::SymbolKind::Function;
HI.NamespaceScope = "";
HI.Definition = "MyRect foobar()";
- HI.Type = {"MyRect ()", "MyRect ()"};
- HI.ReturnType = {"MyRect", "MyRect"};
+ HI.Type = {"MyRect ()", "struct MyRect ()"};
+ HI.ReturnType = {"MyRect", "struct MyRect"};
HI.Parameters.emplace();
}},
{R"cpp(
@@ -3409,7 +3409,8 @@ TEST(Hover, DocsFromMostSpecial) {
TEST(Hover, Present) {
struct {
const std::function<void(HoverInfo &)> Builder;
- llvm::StringRef ExpectedRender;
+ llvm::StringRef ExpectedMarkdownRender;
+ llvm::StringRef ExpectedDoxygenRender;
} Cases[] = {
{
[](HoverInfo &HI) {
@@ -3417,6 +3418,7 @@ TEST(Hover, Present) {
HI.Name = "X";
},
R"(X)",
+ R"(### `X`)",
},
{
[](HoverInfo &HI) {
@@ -3424,6 +3426,7 @@ TEST(Hover, Present) {
HI.Name = "foo";
},
R"(namespace-alias foo)",
+ R"(### namespace-alias `foo`)",
},
{
[](HoverInfo &HI) {
@@ -3446,6 +3449,24 @@ Size: 10 bytes
documentation
template <typename T, typename C = bool> class Foo {})",
+ R"(### class
+
+---
+```cpp
+template <typename T, typename C = bool> class Foo {}
+```
+
+---
+**Template Parameters:**
+
+- `typename T`
+- `typename C = bool`
+
+---
+documentation
+
+---
+Size: 10 bytes)",
},
{
[](HoverInfo &HI) {
@@ -3476,6 +3497,26 @@ template <typename T, typename C = bool> class Foo {})",
"\n"
"// In namespace ns\n"
"ret_type foo(params) {}",
+ R"(### function
+
+---
+```cpp
+// In namespace ns
+ret_type foo(params) {}
+```
+
+---
+**Parameters:**
+
+-
+- `type (aka can_type)`
+- `type foo (aka can_type)`
+- `type foo = default (aka can_type)`
+
+---
+**Returns:**
+
+`ret_type (aka can_ret_type)`)",
},
{
[](HoverInfo &HI) {
@@ -3502,6 +3543,22 @@ Size: 4 bytes (+4 bytes padding), alignment 4 bytes
// In test::Bar
def)",
+ R"(### field
+
+---
+```cpp
+// In test::Bar
+def
+```
+
+---
+Type: `type (aka can_type)`
+
+Value = `value`
+
+Offset: 12 bytes
+
+Size: 4 bytes (+4 bytes padding), alignment 4 bytes)",
},
{
[](HoverInfo &HI) {
@@ -3528,6 +3585,22 @@ Size: 25 bits (+4 bits padding), alignment 8 bytes
// In test::Bar
def)",
+ R"(### field
+
+---
+```cpp
+// In test::Bar
+def
+```
+
+---
+Type: `type (aka can_type)`
+
+Value = `value`
+
+Offset: 4 bytes and 3 bits
+
+Size: 25 bits (+4 bits padding), alignment 8 bytes)",
},
{
[](HoverInfo &HI) {
@@ -3541,6 +3614,13 @@ def)",
// In test::Bar
public: def)",
+ R"(### field
+
+---
+```cpp
+// In test::Bar
+public: def
+```)",
},
{
[](HoverInfo &HI) {
@@ -3560,6 +3640,18 @@ public: def)",
// In cls<int>
protected: size_t method())",
+ R"(### instance-method
+
+---
+```cpp
+// In cls<int>
+protected: size_t method()
+```
+
+---
+**Returns:**
+
+`size_t (aka unsigned long)`)",
},
{
[](HoverInfo &HI) {
@@ -3587,6 +3679,19 @@ Parameters:
// In cls
public: cls(int a, int b = 5))",
+ R"(### constructor
+
+---
+```cpp
+// In cls
+public: cls(int a, int b = 5)
+```
+
+---
+**Parameters:**
+
+- `int a`
+- `int b = 5`)",
},
{
[](HoverInfo &HI) {
@@ -3600,6 +3705,13 @@ public: cls(int a, int b = 5))",
// In namespace ns1
private: union foo {})",
+ R"(### union
+
+---
+```cpp
+// In namespace ns1
+private: union foo {}
+```)",
},
{
[](HoverInfo &HI) {
@@ -3625,6 +3737,20 @@ Passed as arg_a
// In test::Bar
int foo = 3)",
+ R"(### variable
+
+---
+```cpp
+// In test::Bar
+int foo = 3
+```
+
+---
+Type: `int`
+
+Value = `3`
+
+Passed as arg_a)",
},
{
[](HoverInfo &HI) {
@@ -3637,6 +3763,10 @@ int foo = 3)",
R"(variable foo
Passed by value)",
+ R"(### variable `foo`
+
+---
+Passed by value)",
},
{
[](HoverInfo &HI) {
@@ -3662,6 +3792,20 @@ Passed by reference as arg_a
// In test::Bar
int foo = 3)",
+ R"(### variable
+
+---
+```cpp
+// In test::Bar
+int foo = 3
+```
+
+---
+Type: `int`
+
+Value = `3`
+
+Passed by reference as arg_a)",
},
{
[](HoverInfo &HI) {
@@ -3687,6 +3831,20 @@ Passed as arg_a (converted to alias_int)
// In test::Bar
int foo = 3)",
+ R"(### variable
+
+---
+```cpp
+// In test::Bar
+int foo = 3
+```
+
+---
+Type: `int`
+
+Value = `3`
+
+Passed as arg_a (converted to alias_int))",
},
{
[](HoverInfo &HI) {
@@ -3702,6 +3860,15 @@ int foo = 3)",
// Expands to
(1 + 1))",
+ R"(### macro
+
+---
+```cpp
+#define PLUS_ONE(X) (X+1)
+
+// Expands to
+(1 + 1)
+```)",
},
{
[](HoverInfo &HI) {
@@ -3727,38 +3894,283 @@ Passed by const reference as arg_a (converted to int)
// In test::Bar
int foo = 3)",
+ R"(### variable
+
+---
+```cpp
+// In test::Bar
+int foo = 3
+```
+
+---
+Type: `int`
+
+Value = `3`
+
+Passed by const reference as arg_a (converted to int))",
},
{
[](HoverInfo &HI) {
HI.Name = "stdio.h";
HI.Definition = "/usr/include/stdio.h";
+ HI.Kind = index::SymbolKind::IncludeDirective;
},
R"(stdio.h
/usr/include/stdio.h)",
+ R"(### `stdio.h`
+
+`/usr/include/stdio.h`)",
+ },
+ {
+ [](HoverInfo &HI) {
+ HI.Name = "foo.h";
+ HI.UsedSymbolNames = {"Foo", "Bar", "Bar"};
+ HI.Kind = index::SymbolKind::IncludeDirective;
+ },
+ R"(foo.h
+
+provides Foo, Bar, Bar)",
+ R"(### `foo.h`
+
+---
+provides `Foo`, `Bar`, `Bar`)",
},
{[](HoverInfo &HI) {
HI.Name = "foo.h";
- HI.UsedSymbolNames = {"Foo", "Bar", "Bar"};
+ HI.UsedSymbolNames = {"Foo", "Bar", "Baz", "Foobar", "Qux", "Quux"};
+ HI.Kind = index::SymbolKind::IncludeDirective;
},
R"(foo.h
-provides Foo, Bar, Bar)"},
+provides Foo, Bar, Baz, Foobar, Qux and 1 more)",
+ R"(### `foo.h`
+
+---
+provides `Foo`, `Bar`, `Baz`, `Foobar`, `Qux` and 1 more)"}};
+
+ for (const auto &C : Cases) {
+ HoverInfo HI;
+ C.Builder(HI);
+ Config Cfg;
+ Cfg.Hover.ShowAKA = true;
+ Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ EXPECT_EQ(HI.present(MarkupKind::PlainText), C.ExpectedMarkdownRender);
+ }
+ for (const auto &C : Cases) {
+ HoverInfo HI;
+ C.Builder(HI);
+ Config Cfg;
+ Cfg.Hover.ShowAKA = true;
+ Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
+ }
+}
+
+TEST(Hover, PresentDocumentation) {
+ struct {
+ const std::function<void(HoverInfo &)> Builder;
+ llvm::StringRef ExpectedMarkdownRender;
+ llvm::StringRef ExpectedDoxygenRender;
+ } Cases[] = {
{[](HoverInfo &HI) {
- HI.Name = "foo.h";
- HI.UsedSymbolNames = {"Foo", "Bar", "Baz", "Foobar", "Qux", "Quux"};
+ HI.Kind = index::SymbolKind::Function;
+ HI.Documentation = "@brief brief doc\n\n"
+ "longer doc";
+ HI.Definition = "void foo()";
+ HI.Name = "foo";
},
- R"(foo.h
+ R"(### function `foo`
+
+---
+@brief brief doc
+
+longer doc
+
+---
+```cpp
+void foo()
+```)",
+ R"(### function
-provides Foo, Bar, Baz, Foobar, Qux and 1 more)"}};
+---
+```cpp
+void foo()
+```
+
+---
+brief doc
+
+---
+longer doc)"},
+ {[](HoverInfo &HI) {
+ HI.Kind = index::SymbolKind::Function;
+ HI.Documentation = "@brief brief doc\n\n"
+ "longer doc";
+ HI.Definition = "int foo()";
+ HI.ReturnType = "int";
+ HI.Name = "foo";
+ },
+ R"(### function `foo`
+
+---
+→ `int`
+
+@brief brief doc
+
+longer doc
+
+---
+```cpp
+int foo()
+```)",
+ R"(### function
+
+---
+```cpp
+int foo()
+```
+
+---
+brief doc
+
+---
+**Returns:**
+
+`int`
+
+---
+longer doc)"},
+ {[](HoverInfo &HI) {
+ HI.Kind = index::SymbolKind::Function;
+ HI.Documentation = "@brief brief doc\n\n"
+ "longer doc\n@param a this is a param\n@return it "
+ "returns something";
+ HI.Definition = "int foo(int a)";
+ HI.ReturnType = "int";
+ HI.Name = "foo";
+ HI.Parameters.emplace();
+ HI.Parameters->emplace_back();
+ HI.Parameters->back().Type = "int";
+ HI.Parameters->back().Name = "a";
+ },
+ R"(### function `foo`
+
+---
+→ `int`
+
+Parameters:
+
+- `int a`
+
+@brief brief doc
+
+longer doc
+@param a this is a param
+@return it returns something
+
+---
+```cpp
+int foo(int a)
+```)",
+ R"(### function
+
+---
+```cpp
+int foo(int a)
+```
+
+---
+brief doc
+
+---
+**Parameters:**
+
+- `int a` - this is a param
+
+---
+**Returns:**
+
+`int` - it returns something
+
+---
+longer doc)"},
+ {[](HoverInfo &HI) {
+ HI.Kind = index::SymbolKind::Function;
+ HI.Documentation = "@brief brief doc\n\n"
+ "longer doc\n@param a this is a param\n@param b "
+ "does not exist\n@return it returns something";
+ HI.Definition = "int foo(int a)";
+ HI.ReturnType = "int";
+ HI.Name = "foo";
+ HI.Parameters.emplace();
+ HI.Parameters->emplace_back();
+ HI.Parameters->back().Type = "int";
+ HI.Parameters->back().Name = "a";
+ },
+ R"(### function `foo`
+
+---
+→ `int`
+
+Parameters:
+
+- `int a`
+
+@brief brief doc
+
+longer doc
+@param a this is a param
+@param b does not exist
+@return it returns something
+
+---
+```cpp
+int foo(int a)
+```)",
+ R"(### function
+
+---
+```cpp
+int foo(int a)
+```
+
+---
+brief doc
+
+---
+**Parameters:**
+
+- `int a` - this is a param
+
+---
+**Returns:**
+
+`int` - it returns something
+
+---
+longer doc)"},
+ };
for (const auto &C : Cases) {
HoverInfo HI;
C.Builder(HI);
Config Cfg;
Cfg.Hover.ShowAKA = true;
+ Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
WithContextValue WithCfg(Config::Key, std::move(Cfg));
- EXPECT_EQ(HI.present(MarkupKind::PlainText), C.ExpectedRender);
+ EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedMarkdownRender);
+ }
+ for (const auto &C : Cases) {
+ HoverInfo HI;
+ C.Builder(HI);
+ Config Cfg;
+ Cfg.Hover.ShowAKA = true;
+ Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
}
}
@@ -3936,6 +4348,21 @@ TEST(Hover, PresentRulers) {
"```";
EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedMarkdown);
+ llvm::StringRef ExpectedDoxygenMarkdown = //
+ "### variable\n"
+ "\n"
+ "---\n"
+ "```cpp\n"
+ "def\n"
+ "```\n\n"
+ "---\n"
+ "Value = `val`";
+ Config Cfg;
+ Cfg.Hover.ShowAKA = true;
+ Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedDoxygenMarkdown);
+
llvm::StringRef ExpectedPlaintext = R"pt(variable foo
Value = val
@@ -4339,6 +4766,188 @@ constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) {
EXPECT_TRUE(H->Value);
EXPECT_TRUE(H->Type);
}
+
+TEST(Hover, HoverMacroContentsLimit) {
+ const char *const Code =
+ R"cpp(
+ #define C(A) A##A // Concatenate
+ #define E(A) C(A) // Expand
+ #define Z0032 00000000000000000000000000000000
+ #define Z0064 E(Z0032)
+ #define Z0128 E(Z0064)
+ #define Z0256 E(Z0128)
+ #define Z0512 E(Z0256)
+ #define Z1024 E(Z0512)
+ #define Z2048 E(Z1024)
+ #define Z4096 E(Z2048) // 4096 zeroes
+ int main() { return [[^Z4096]]; }
+ )cpp";
+
+ struct {
+ uint32_t MacroContentsLimit;
+ const std::string ExpectedDefinition;
+ } Cases[] = {
+ // With a limit of 2048, the macro expansion should get dropped.
+ {2048, "#define Z4096 E(Z2048)"},
+ // With a limit of 8192, the macro expansion should be fully expanded.
+ {8192, std::string("#define Z4096 E(Z2048)\n\n") +
+ std::string("// Expands to\n") + std::string(4096, '0')},
+ };
+ for (const auto &Case : Cases) {
+ SCOPED_TRACE(Code);
+
+ Annotations T(Code);
+ TestTU TU = TestTU::withCode(T.code());
+ auto AST = TU.build();
+ Config Cfg;
+ Cfg.Hover.MacroContentsLimit = Case.MacroContentsLimit;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+ ASSERT_TRUE(H);
+
+ EXPECT_EQ(H->Definition, Case.ExpectedDefinition);
+ }
+}
+
+TEST(Hover, FunctionParameters) {
+ struct {
+ const char *const Code;
+ const std::function<void(HoverInfo &)> ExpectedBuilder;
+ std::string ExpectedRender;
+ } Cases[] = {
+ {R"cpp(/// Function doc
+ void foo(int [[^a]]);
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "a";
+ HI.Kind = index::SymbolKind::Parameter;
+ HI.NamespaceScope = "";
+ HI.LocalScope = "foo::";
+ HI.Type = "int";
+ HI.Definition = "int a";
+ HI.Documentation = "";
+ },
+ "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
+ {R"cpp(/// Function doc
+ /// @param a this is doc for a
+ void foo(int [[^a]]);
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "a";
+ HI.Kind = index::SymbolKind::Parameter;
+ HI.NamespaceScope = "";
+ HI.LocalScope = "foo::";
+ HI.Type = "int";
+ HI.Definition = "int a";
+ HI.Documentation = "this is doc for a";
+ },
+ "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthis is doc "
+ "for a\n\n---\nType: `int`"},
+ {R"cpp(/// Function doc
+ /// @param b this is doc for b
+ void foo(int [[^a]], int b);
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "a";
+ HI.Kind = index::SymbolKind::Parameter;
+ HI.NamespaceScope = "";
+ HI.LocalScope = "foo::";
+ HI.Type = "int";
+ HI.Definition = "int a";
+ HI.Documentation = "";
+ },
+ "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
+ {R"cpp(/// Function doc
+ /// @param b this is doc for \p b
+ void foo(int a, int [[^b]]);
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "b";
+ HI.Kind = index::SymbolKind::Parameter;
+ HI.NamespaceScope = "";
+ HI.LocalScope = "foo::";
+ HI.Type = "int";
+ HI.Definition = "int b";
+ HI.Documentation = "this is doc for \\p b";
+ },
+ "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is doc "
+ "for `b`\n\n---\nType: `int`"},
+ {R"cpp(/// Function doc
+ /// @param b this is doc for \p b
+ template <typename T>
+ void foo(T a, T [[^b]]);
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "b";
+ HI.Kind = index::SymbolKind::Parameter;
+ HI.NamespaceScope = "";
+ HI.LocalScope = "foo::";
+ HI.Type = "T";
+ HI.Definition = "T b";
+ HI.Documentation = "this is doc for \\p b";
+ },
+ "### param\n\n---\n```cpp\n// In foo\nT b\n```\n\n---\nthis is doc for "
+ "`b`\n\n---\nType: `T`"},
+ {R"cpp(/// Function doc
+ /// @param b this is <b>doc</b> <html-tag attribute/> <another-html-tag attribute="value">for</another-html-tag> \p b
+ void foo(int a, int [[^b]]);
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "b";
+ HI.Kind = index::SymbolKind::Parameter;
+ HI.NamespaceScope = "";
+ HI.LocalScope = "foo::";
+ HI.Type = "int";
+ HI.Definition = "int b";
+ HI.Documentation =
+ "this is <b>doc</b> <html-tag attribute/> <another-html-tag "
+ "attribute=\"value\">for</another-html-tag> \\p b";
+ },
+ "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is "
+ "\\<b>doc\\</b> \\<html-tag attribute/> \\<another-html-tag "
+ "attribute=\"value\">for\\</another-html-tag> `b`\n\n---\nType: `int`"},
+ };
+
+ // Create a tiny index, so tests above can verify documentation is fetched.
+ Symbol IndexSym = func("indexSymbol");
+ IndexSym.Documentation = "comment from index";
+ SymbolSlab::Builder Symbols;
+ Symbols.insert(IndexSym);
+ auto Index =
+ MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
+
+ for (const auto &Case : Cases) {
+ SCOPED_TRACE(Case.Code);
+
+ Annotations T(Case.Code);
+ TestTU TU = TestTU::withCode(T.code());
+ auto AST = TU.build();
+ Config Cfg;
+ Cfg.Hover.ShowAKA = true;
+ Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
+ ASSERT_TRUE(H);
+ HoverInfo Expected;
+ Expected.SymRange = T.range();
+ Case.ExpectedBuilder(Expected);
+
+ EXPECT_EQ(H->present(MarkupKind::Markdown), Case.ExpectedRender);
+ EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
+ EXPECT_EQ(H->LocalScope, Expected.LocalScope);
+ EXPECT_EQ(H->Name, Expected.Name);
+ EXPECT_EQ(H->Kind, Expected.Kind);
+ EXPECT_EQ(H->Documentation, Expected.Documentation);
+ EXPECT_EQ(H->Definition, Expected.Definition);
+ EXPECT_EQ(H->Type, Expected.Type);
+ EXPECT_EQ(H->ReturnType, Expected.ReturnType);
+ EXPECT_EQ(H->Parameters, Expected.Parameters);
+ EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
+ EXPECT_EQ(H->SymRange, Expected.SymRange);
+ EXPECT_EQ(H->Value, Expected.Value);
+ }
+}
+
} // namespace
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index e0cd955..99e728c 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1295,14 +1295,7 @@ TEST(TypeHints, NoQualifiers) {
}
}
)cpp",
- ExpectedHint{": S1", "x"},
- // FIXME: We want to suppress scope specifiers
- // here because we are into the whole
- // brevity thing, but the ElaboratedType
- // printer does not honor the SuppressScope
- // flag by design, so we need to extend the
- // PrintingPolicy to support this use case.
- ExpectedHint{": S2::Inner<int>", "y"});
+ ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"});
}
TEST(TypeHints, Lambda) {
diff --git a/clang-tools-extra/clangd/unittests/QualityTests.cpp b/clang-tools-extra/clangd/unittests/QualityTests.cpp
index 619ea32..4954659 100644
--- a/clang-tools-extra/clangd/unittests/QualityTests.cpp
+++ b/clang-tools-extra/clangd/unittests/QualityTests.cpp
@@ -121,7 +121,9 @@ TEST(QualityTests, SymbolRelevanceSignalExtraction) {
SymbolRelevanceSignals Relevance;
Relevance.merge(CodeCompletionResult(&findDecl(AST, "deprecated"),
- /*Priority=*/42, nullptr, false,
+ /*Priority=*/42,
+ /*Qualifier=*/std::nullopt,
+ /*QualifierIsInformative=*/false,
/*Accessible=*/false));
EXPECT_EQ(Relevance.NameMatch, SymbolRelevanceSignals().NameMatch);
EXPECT_TRUE(Relevance.Forbidden);
@@ -487,13 +489,15 @@ TEST(QualityTests, ItemWithFixItsRankedDown) {
auto AST = Header.build();
SymbolRelevanceSignals RelevanceWithFixIt;
- RelevanceWithFixIt.merge(CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr,
- false, true, {FixItHint{}}));
+ RelevanceWithFixIt.merge(CodeCompletionResult(
+ &findDecl(AST, "x"), /*Priority=*/0, /*Qualifier=*/std::nullopt,
+ /*QualifierIsInformative=*/false, /*Accessible=*/true, {FixItHint{}}));
EXPECT_TRUE(RelevanceWithFixIt.NeedsFixIts);
SymbolRelevanceSignals RelevanceWithoutFixIt;
- RelevanceWithoutFixIt.merge(
- CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, false, true, {}));
+ RelevanceWithoutFixIt.merge(CodeCompletionResult(
+ &findDecl(AST, "x"), /*Priority=*/0, /*Qualifier=*/std::nullopt,
+ /*QualifierIsInformative=*/false, /*Accessible=*/true, {}));
EXPECT_FALSE(RelevanceWithoutFixIt.NeedsFixIts);
EXPECT_LT(RelevanceWithFixIt.evaluateHeuristics(),
diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp
index 2cb0722..5d2a77b 100644
--- a/clang-tools-extra/clangd/unittests/RenameTests.cpp
+++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp
@@ -17,10 +17,11 @@
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <algorithm>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <algorithm>
+
namespace clang {
namespace clangd {
namespace {
@@ -861,6 +862,25 @@ TEST(RenameTest, WithinFileRename) {
void func([[Fo^o]] *f) {}
)cpp",
+
+ // rename with explicit object parameter
+ R"cpp(
+ struct Foo {
+ int [[memb^er]] {};
+ auto&& getter1(this auto&& self) {
+ auto local = [&] {
+ return self.[[memb^er]];
+ }();
+ return local + self.[[memb^er]];
+ }
+ auto&& getter2(this Foo&& self) {
+ return self.[[memb^er]];
+ }
+ int normal() {
+ return this->[[mem^ber]] + [[memb^er]];
+ }
+ };
+ )cpp",
};
llvm::StringRef NewName = "NewName";
for (llvm::StringRef T : Tests) {
@@ -868,6 +888,7 @@ TEST(RenameTest, WithinFileRename) {
Annotations Code(T);
auto TU = TestTU::withCode(Code.code());
TU.ExtraArgs.push_back("-xobjective-c++");
+ TU.ExtraArgs.push_back("-std=c++23");
auto AST = TU.build();
auto Index = TU.index();
for (const auto &RenamePos : Code.points()) {
diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
index aaaf758..3df19d8 100644
--- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -104,9 +104,9 @@ TEST(SelectionTest, CommonAncestor) {
{
R"cpp(
template <typename T>
- int x = [[T::^U::]]ccc();
+ int x = T::[[^U]]::ccc();
)cpp",
- "NestedNameSpecifierLoc",
+ "DependentNameTypeLoc",
},
{
R"cpp(
diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
index 7ede19c..4efae25 100644
--- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
@@ -371,6 +371,45 @@ TEST(FoldingRanges, PseudoParserWithoutLineFoldings) {
//[[ foo
/* bar */]]
)cpp",
+ R"cpp(
+ //Ignore non-conditional directives
+ #define A 1
+
+ void func() {[[
+ int Variable = 100;
+
+ #ifdef FOO[[
+ Variable = 1;
+ #if 1[[
+ Variable = 4;
+ ]]#endif
+ ]]#else[[
+ Variable = 2;
+ //handle nested directives
+ #if 1[[
+ Variable = 3;
+ ]]#endif
+ ]]#endif
+
+
+ ]]}
+ )cpp",
+ R"cpp(
+ int Variable = 0;
+ #if defined(WALDO)
+ Variable = 1;
+ #
+ )cpp",
+ R"cpp(
+ int Variable = 0;
+ #if defined(WALDO)[[
+ Variable = 1;
+ ]]#elif 1[[
+ Variable = 2;
+ ]]#else
+ Variable = 3;
+ #
+ )cpp",
};
for (const char *Test : Tests) {
auto T = Annotations(Test);
diff --git a/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp b/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp
new file mode 100644
index 0000000..31a6a14
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp
@@ -0,0 +1,215 @@
+//===-- SymbolDocumentationTests.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "SymbolDocumentation.h"
+
+#include "support/Markup.h"
+#include "clang/Basic/CommentOptions.h"
+#include "llvm/ADT/StringRef.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+TEST(SymbolDocumentation, UnhandledDocs) {
+
+ CommentOptions CommentOpts;
+
+ struct Case {
+ llvm::StringRef Documentation;
+ llvm::StringRef ExpectedRenderEscapedMarkdown;
+ llvm::StringRef ExpectedRenderMarkdown;
+ llvm::StringRef ExpectedRenderPlainText;
+ } Cases[] = {
+ {
+ "foo bar",
+ "foo bar",
+ "foo bar",
+ "foo bar",
+ },
+ {
+ "foo\nbar\n",
+ "foo\nbar",
+ "foo\nbar",
+ "foo bar",
+ },
+ {
+ "foo\n\nbar\n",
+ "foo\n\nbar",
+ "foo\n\nbar",
+ "foo\n\nbar",
+ },
+ {
+ "foo \\p bar baz",
+ "foo `bar` baz",
+ "foo `bar` baz",
+ "foo bar baz",
+ },
+ {
+ "foo \\e bar baz",
+ "foo \\*bar\\* baz",
+ "foo *bar* baz",
+ "foo *bar* baz",
+ },
+ {
+ "foo \\b bar baz",
+ "foo \\*\\*bar\\*\\* baz",
+ "foo **bar** baz",
+ "foo **bar** baz",
+ },
+ {
+ "foo \\ref bar baz",
+ "foo \\*\\*\\\\ref\\*\\* \\*bar\\* baz",
+ "foo **\\ref** *bar* baz",
+ "foo **\\ref** *bar* baz",
+ },
+ {
+ "foo @ref bar baz",
+ "foo \\*\\*@ref\\*\\* \\*bar\\* baz",
+ "foo **@ref** *bar* baz",
+ "foo **@ref** *bar* baz",
+ },
+ {
+ "\\brief this is a \\n\nbrief description",
+ "",
+ "",
+ "",
+ },
+ {
+ "\\throw exception foo",
+ "\\*\\*\\\\throw\\*\\* \\*exception\\* foo",
+ "**\\throw** *exception* foo",
+ "**\\throw** *exception* foo",
+ },
+ {
+ R"(\brief this is a brief description
+
+\li item 1
+\li item 2
+\arg item 3)",
+ R"(- item 1
+
+- item 2
+
+- item 3)",
+ R"(- item 1
+
+- item 2
+
+- item 3)",
+ R"(- item 1
+
+- item 2
+
+- item 3)",
+ },
+ {
+ "\\defgroup mygroup this is a group\nthis is not a group description",
+ "\\*\\*@defgroup\\*\\* `mygroup this is a group`\n\nthis is not a "
+ "group "
+ "description",
+ "**@defgroup** `mygroup this is a group`\n\nthis is not a group "
+ "description",
+ "**@defgroup** `mygroup this is a group`\n\nthis is not a group "
+ "description",
+ },
+ {
+ R"(\verbatim
+this is a
+verbatim block containing
+some verbatim text
+\endverbatim)",
+ R"(\*\*@verbatim\*\*
+
+```
+this is a
+verbatim block containing
+some verbatim text
+```
+
+\*\*@endverbatim\*\*)",
+ R"(**@verbatim**
+
+```
+this is a
+verbatim block containing
+some verbatim text
+```
+
+**@endverbatim**)",
+ R"(**@verbatim**
+
+this is a
+verbatim block containing
+some verbatim text
+
+**@endverbatim**)",
+ },
+ {
+ "@param foo this is a parameter\n@param bar this is another "
+ "parameter",
+ "",
+ "",
+ "",
+ },
+ {
+ R"(@brief brief docs
+
+@param foo this is a parameter
+
+\brief another brief?
+
+\details these are details
+
+More description
+documentation)",
+ R"(\*\*\\brief\*\* another brief?
+
+\*\*\\details\*\* these are details
+
+More description
+documentation)",
+ R"(**\brief** another brief?
+
+**\details** these are details
+
+More description
+documentation)",
+ R"(**\brief** another brief?
+
+**\details** these are details
+
+More description documentation)",
+ },
+ {
+ R"(<b>this is a bold text</b>
+normal text<i>this is an italic text</i>
+<code>this is a code block</code>)",
+ R"(\<b>this is a bold text\</b>
+normal text\<i>this is an italic text\</i>
+\<code>this is a code block\</code>)",
+ R"(\<b>this is a bold text\</b>
+normal text\<i>this is an italic text\</i>
+\<code>this is a code block\</code>)",
+ "<b>this is a bold text</b> normal text<i>this is an italic text</i> "
+ "<code>this is a code block</code>",
+ },
+ };
+ for (const auto &C : Cases) {
+ markup::Document Doc;
+ SymbolDocCommentVisitor SymbolDoc(C.Documentation, CommentOpts);
+
+ SymbolDoc.docToMarkup(Doc);
+
+ EXPECT_EQ(Doc.asPlainText(), C.ExpectedRenderPlainText);
+ EXPECT_EQ(Doc.asMarkdown(), C.ExpectedRenderMarkdown);
+ EXPECT_EQ(Doc.asEscapedMarkdown(), C.ExpectedRenderEscapedMarkdown);
+ }
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp b/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp
index 482f230..5f91f31 100644
--- a/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp
+++ b/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp
@@ -463,6 +463,7 @@ TEST(Document, Separators) {
```cpp
test
```
+
bar)md";
EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown);
EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);
@@ -559,6 +560,7 @@ foo
bar
baz
```
+
```cpp
foo
```)md";
@@ -571,6 +573,12 @@ foo
foo)pt";
EXPECT_EQ(D.asPlainText(), ExpectedPlainText);
+
+ Document D2;
+ D2.addCodeBlock("");
+ EXPECT_EQ(D2.asEscapedMarkdown(), "```cpp\n```");
+ EXPECT_EQ(D2.asMarkdown(), "```cpp\n```");
+ EXPECT_EQ(D2.asPlainText(), "");
}
TEST(BulletList, Render) {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8b636018..32e4dfb 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -1,3 +1,6 @@
+.. If you want to modify sections/contents permanently, you should modify both
+ ReleaseNotes.rst and ReleaseNotesTemplate.txt.
+
====================================================
Extra Clang Tools |release| |ReleaseNotesTitle|
====================================================
@@ -101,6 +104,14 @@ Improvements to clang-query
Improvements to clang-tidy
--------------------------
+- The :program:`check_clang_tidy.py` tool now recognizes the ``-std`` argument
+ when run over C files. If ``-std`` is not specified, it defaults to
+ ``c99-or-later``.
+
+- :program:`clang-tidy` no longer attemps to analyze code from system headers
+ by default, greatly improving performance. This behavior is disabled if the
+ `SystemHeaders` option is enabled.
+
- The :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` scripts
now run checks in parallel by default using all available hardware threads.
Both scripts display the number of threads being used in their output.
@@ -109,6 +120,12 @@ Improvements to clang-tidy
`enable-check-profile` to enable per-check timing profiles and print a
report based on all analyzed files.
+- Improved documentation of the `-line-filter` command-line flag of
+ :program:`clang-tidy` and :program:`run-clang-tidy.py`.
+
+- Improved :program:`clang-tidy` option `-quiet` by suppressing diagnostic
+ count messages.
+
New checks
^^^^^^^^^^
@@ -118,12 +135,25 @@ New checks
Detects default initialization (to 0) of variables with ``enum`` type where
the enum has no enumerator with value of 0.
+- New :doc:`cppcoreguidelines-pro-bounds-avoid-unchecked-container-access
+ <clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access>`
+ check.
+
+ Finds calls to ``operator[]`` in STL containers and suggests replacing them
+ with safe alternatives.
+
- New :doc:`llvm-mlir-op-builder
<clang-tidy/checks/llvm/use-new-mlir-op-builder>` check.
Checks for uses of MLIR's old/to be deprecated ``OpBuilder::create<T>`` form
and suggests using ``T::create`` instead.
+- New :doc:`misc-override-with-different-visibility
+ <clang-tidy/checks/misc/override-with-different-visibility>` check.
+
+ Finds virtual function overrides with different visibility than the function
+ in the base class.
+
New check aliases
^^^^^^^^^^^^^^^^^
@@ -140,7 +170,7 @@ Changes in existing checks
- Improved :doc:`bugprone-reserved-identifier
<clang-tidy/checks/bugprone/reserved-identifier>` check by ignoring
- declarations in system headers.
+ declarations and macros in system headers.
- Improved :doc:`bugprone-signed-char-misuse
<clang-tidy/checks/bugprone/signed-char-misuse>` check by fixing
@@ -157,9 +187,23 @@ Changes in existing checks
an additional matcher that generalizes the copy-and-swap idiom pattern
detection.
+- Improved :doc:`cppcoreguidelines-prefer-member-initializer
+ <clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>` check to
+ avoid false positives on inherited members in class templates.
+
+- Improved :doc:`cppcoreguidelines-pro-bounds-pointer-arithmetic
+ <clang-tidy/checks/cppcoreguidelines/pro-bounds-pointer-arithmetic>` check
+ adding an option to allow pointer arithmetic via prefix/postfix increment or
+ decrement operators.
+
- Improved :doc:`misc-header-include-cycle
<clang-tidy/checks/misc/header-include-cycle>` check performance.
+- Improved :doc:`modernize-use-constraints
+ <clang-tidy/checks/modernize/use-constraints>` check by fixing a crash on
+ uses of non-standard ``enable_if`` with a signature different from
+ ``std::enable_if`` (such as ``boost::enable_if``).
+
- Improved :doc:`modernize-use-designated-initializers
<clang-tidy/checks/modernize/use-designated-initializers>` check to
suggest using designated initializers for aliased aggregate types.
@@ -186,14 +230,25 @@ Changes in existing checks
<clang-tidy/checks/portability/template-virtual-member-function>` check to
avoid false positives on pure virtual member functions.
+- Improved :doc:`readability-container-size-empty
+ <clang-tidy/checks/readability/container-size-empty>` check by correctly
+ generating fix-it hints when size method is called from implicit ``this``,
+ ignoring default constructors with user provided arguments and adding
+ detection in container's method except ``empty``.
+
- Improved :doc:`readability-identifier-naming
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
- declarations in system headers.
+ declarations and macros in system headers. The documentation is also improved
+ to differentiate the general options from the specific ones.
- Improved :doc:`readability-qualified-auto
<clang-tidy/checks/readability/qualified-auto>` check by adding the option
`IgnoreAliasing`, that allows not looking at underlying types of type aliases.
+- Improved :doc:`readability-uppercase-literal-suffix
+ <clang-tidy/checks/readability/uppercase-literal-suffix>` check to recognize
+ literal suffixes added in C++23 and C23.
+
Removed checks
^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/ReleaseNotesTemplate.txt b/clang-tools-extra/docs/ReleaseNotesTemplate.txt
new file mode 100644
index 0000000..b17799b
--- /dev/null
+++ b/clang-tools-extra/docs/ReleaseNotesTemplate.txt
@@ -0,0 +1,122 @@
+.. If you want to modify sections/contents permanently, you should modify both
+ ReleaseNotes.rst and ReleaseNotesTemplate.txt.
+
+====================================================
+Extra Clang Tools |release| |ReleaseNotesTitle|
+====================================================
+
+.. contents::
+ :local:
+ :depth: 3
+
+Written by the `LLVM Team <https://llvm.org/>`_
+
+.. only:: PreRelease
+
+ .. warning::
+ These are in-progress notes for the upcoming Extra Clang Tools |version| release.
+ Release notes for previous releases can be found on
+ `the Download Page <https://releases.llvm.org/download.html>`_.
+
+Introduction
+============
+
+This document contains the release notes for the Extra Clang Tools, part of the
+Clang release |release|. Here we describe the status of the Extra Clang Tools in
+some detail, including major improvements from the previous release and new
+feature work. All LLVM releases may be downloaded from the `LLVM releases web
+site <https://llvm.org/releases/>`_.
+
+For more information about Clang or LLVM, including information about
+the latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or
+the `LLVM Web Site <https://llvm.org>`_.
+
+Note that if you are reading this file from a Git checkout or the
+main Clang web page, this document applies to the *next* release, not
+the current one. To see the release notes for a specific release, please
+see the `releases page <https://llvm.org/releases/>`_.
+
+What's New in Extra Clang Tools |release|?
+==========================================
+
+Some of the major new features and improvements to Extra Clang Tools are listed
+here. Generic improvements to Extra Clang Tools as a whole or to its underlying
+infrastructure are described first, followed by tool-specific sections.
+
+Major New Features
+------------------
+
+Improvements to clangd
+----------------------
+
+Inlay hints
+^^^^^^^^^^^
+
+Diagnostics
+^^^^^^^^^^^
+
+Semantic Highlighting
+^^^^^^^^^^^^^^^^^^^^^
+
+Compile flags
+^^^^^^^^^^^^^
+
+Hover
+^^^^^
+
+Code completion
+^^^^^^^^^^^^^^^
+
+Code actions
+^^^^^^^^^^^^
+
+Signature help
+^^^^^^^^^^^^^^
+
+Cross-references
+^^^^^^^^^^^^^^^^
+
+Objective-C
+^^^^^^^^^^^
+
+Miscellaneous
+^^^^^^^^^^^^^
+
+Improvements to clang-doc
+-------------------------
+
+Improvements to clang-query
+---------------------------
+
+Improvements to clang-tidy
+--------------------------
+
+New checks
+^^^^^^^^^^
+
+New check aliases
+^^^^^^^^^^^^^^^^^
+
+Changes in existing checks
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Removed checks
+^^^^^^^^^^^^^^
+
+Miscellaneous
+^^^^^^^^^^^^^
+
+Improvements to include-fixer
+-----------------------------
+
+Improvements to clang-include-fixer
+-----------------------------------
+
+Improvements to modularize
+--------------------------
+
+Improvements to pp-trace
+------------------------
+
+Clang-tidy Visual Studio plugin
+-------------------------------
diff --git a/clang-tools-extra/docs/clang-change-namespace.rst b/clang-tools-extra/docs/clang-change-namespace.rst
new file mode 100644
index 0000000..1eab83f
--- /dev/null
+++ b/clang-tools-extra/docs/clang-change-namespace.rst
@@ -0,0 +1,314 @@
+======================
+Clang-Change-Namespace
+======================
+
+.. contents::
+
+.. toctree::
+ :maxdepth: 1
+
+:program:`clang-change-namespace` can be used to change the surrounding
+namespaces of class/function definitions.
+
+Classes/functions in the moved namespace will have new namespaces while
+references to symbols (e.g. types, functions) which are not defined in the
+changed namespace will be correctly qualified by prepending namespace specifiers
+before them. This will try to add shortest namespace specifiers possible.
+
+When a symbol reference needs to be fully-qualified, this adds a `::` prefix to
+the namespace specifiers unless the new namespace is the global namespace. For
+classes, only classes that are declared/defined in the given namespace in
+specified files will be moved: forward declarations will remain in the old
+namespace. The will be demonstrated in the next example.
+
+Example usage
+-------------
+
+For example, consider this `test.cc` example here with the forward declared
+class `FWD` and the defined class `A`, both in the namespace `a`.
+
+.. code-block:: c++
+
+ namespace a {
+ class FWD;
+ class A {
+ FWD *fwd;
+ };
+ } // namespace a
+
+And now let's change the namespace `a` to `x`.
+
+.. code-block:: console
+
+ clang-change-namespace \
+ --old_namespace "a" \
+ --new_namespace "x" \
+ --file_pattern "test.cc" \
+ --i \
+ test.cc
+
+Note that in the code below there's still the forward decalred class `FWD` that
+stayed in the namespace `a`. It wasn't moved to the new namespace because it
+wasn't defined/declared here in `a` but only forward declared.
+
+.. code-block:: c++
+
+ namespace a {
+ class FWD;
+ } // namespace a
+ namespace x {
+
+ class A {
+ a::FWD *fwd;
+ };
+ } // namespace x
+
+
+Another example
+---------------
+
+Consider this `test.cc` file:
+
+.. code-block:: c++
+
+ namespace na {
+ class X {};
+ namespace nb {
+ class Y {
+ X x;
+ };
+ } // namespace nb
+ } // namespace na
+
+To move the definition of class `Y` from namespace `na::nb` to `x::y`, run:
+
+.. code-block:: console
+
+ clang-change-namespace \
+ --old_namespace "na::nb" \
+ --new_namespace "x::y" \
+ --file_pattern "test.cc" \
+ --i \
+ test.cc
+
+This will overwrite `test.cc` to look like this:
+
+.. code-block:: c++
+
+ namespace na {
+ class X {};
+
+ } // namespace na
+ namespace x {
+ namespace y {
+ class Y {
+ na::X x;
+ };
+ } // namespace y
+ } // namespace x
+
+Note, that we've successfully moved the class `Y` from namespace `na::nb` to
+namespace `x::y`.
+
+Caveats
+=======
+
+Content already exists in new namespace
+---------------------------------------
+
+Consider this `test.cc` example that defines two `class A` one inside the
+namespace `a` and one in namespace `b`:
+
+.. code-block:: c++
+
+ namespace a {
+ class A {
+ int classAFromWithinNamespace_a;
+ };
+ } // namespace a
+
+ namespace b {
+ class A {
+ int classAFromWithinNamespace_b;
+ };
+ } //namespace b
+
+Let's move everything from namespace `a` to namespace `b`:
+
+.. code-block:: console
+
+ clang-change-namespace \
+ --old_namespace "a" \
+ --new_namespace "b" \
+ --file_pattern test.cc \
+ test.cc
+
+As expected we now have to definitions of `class A` inside the namespace `b`:
+
+.. code-block:: c++
+
+ namespace b {
+ class A {
+ int classAFromWithinNamespace_a;
+ };
+ } // namespace b
+
+ namespace b {
+ class A {
+ int classAFromWithinNamespace_b;
+ };
+ } //namespace b
+
+The re-factoring looks correct but the code will not compile due to the name
+duplication. It is not up to the tool to ensure compilability in that sense.
+But one has to be aware of that.
+
+Inline namespace doesn't work
+-----------------------------
+
+Consider this usage of two versions of implementations for a `greet` function:
+
+.. code-block:: c++
+
+ #include <cstdio>
+
+ namespace Greeter {
+ inline namespace Version1 {
+ const char* greet() { return "Hello from version 1!"; }
+ } // namespace Version1
+ namespace Version2 {
+ const char* greet() { return "Hello from version 2!"; }
+ } // namespace Version2
+ } // namespace Greeter
+
+ int main(int argc, char* argv[]) {
+ printf("%s\n", Greeter::greet());
+ return 0;
+ }
+
+Note, that currently `Greeter::greet()` will result in a call to
+`Greeter::Version1::greet()` because that's the inlined namespace.
+
+Let's say you want to move one and make `Version2` the default now and remove
+the `inline` from the `Version1`. First let's try to turn `namespace Version2`
+into `inline namespace Version2`:
+
+.. code-block:: console
+
+ clang-change-namespace \
+ --old_namespace "Greeter::Version2" \
+ --new_namespace "inline Version2" \
+ --file_pattern main.cc main.cc
+
+But this will put the `inline` keyword in the wrong place resulting in:
+
+.. code-block:: c++
+
+ #include <cstdio>
+
+ namespace Greeter {
+ inline namespace Version1 {
+ const char* greet() { return "Hello from version 1!"; }
+ } // namespace Version1
+
+ } // namespace Greeter
+ namespace inline Greeter {
+ namespace Version2 {
+ const char *greet() { return "Hello from version 2!"; }
+ } // namespace Version2
+ } // namespace inline Greeter
+
+ int main(int argc, char* argv[]) {
+ printf("%s\n", Greeter::greet());
+ return 0;
+ }
+
+One cannot use `:program:`clang-change-namespace` to inline a namespace.
+
+Symbol references not updated
+-----------------------------
+
+Consider this `test.cc` file:
+
+.. code-block:: c++
+
+ namespace old {
+ struct foo {};
+ } // namespace old
+
+ namespace b {
+ old::foo g_foo;
+ } // namespace b
+
+Notice that namespace `b` defines a global variable of type `old::foo`. If we
+now change the name of the `old` namespace to `modern`, the reference will not
+be updated:
+
+.. code-block:: console
+
+ clang-change-namespace \
+ --old_namespace "old" \
+ --new_namespace "modern" \
+ --file_pattern test.cc \
+ test.cc
+
+.. code-block:: c++
+
+ namespace modern {
+ struct foo {};
+ } // namespace modern
+
+ namespace b {
+ old::foo g_foo;
+ } // namespace b
+
+`g_foo` is still of the no longer existing type `old::foo` while instead it
+should use `modern::foo`.
+
+Only symbol references in the moved namespace are updated, not outside of it.
+
+
+:program:`clang-change-namespace` Command Line Options
+======================================================
+
+.. option:: --allowed_file=<string>
+
+ A file containing regexes of symbol names that are not expected to be updated
+ when changing namespaces around them.
+
+.. option:: --dump_result
+
+ Dump new file contents in YAML, if specified.
+
+.. option:: --extra-arg=<string>
+
+ Additional argument to append to the compiler command line
+
+.. option:: --extra-arg-before=<string>
+
+ Additional argument to prepend to the compiler command line
+
+.. option:: --file_pattern=<string>
+
+ Only rename namespaces in files that match the given regular expression
+ pattern.
+
+.. option:: -i
+
+ Inplace edit <file>s, if specified.
+
+.. option:: --new_namespace=<string>
+
+ New namespace. Use `""` when you target the global namespace.
+
+.. option:: --old_namespace=<string>
+
+ Old namespace.
+
+.. option:: -p <string>
+
+ Build path
+
+.. option:: --style=<string>
+
+ The style name used for reformatting.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.rst
new file mode 100644
index 0000000..556d902
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.rst
@@ -0,0 +1,64 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-bounds-avoid-unchecked-container-access
+
+cppcoreguidelines-pro-bounds-avoid-unchecked-container-access
+=============================================================
+
+Finds calls to ``operator[]`` in STL containers and suggests replacing them
+with safe alternatives.
+Safe alternatives include STL ``at`` or GSL ``at`` functions, ``begin()`` or
+``end()`` functions, ``range-for`` loops, ``std::span``, or an appropriate
+function from ``<algorithms>``.
+
+For example, both
+
+.. code-block:: c++
+
+ std::vector<int> a;
+ int b = a[4];
+
+and
+
+.. code-block:: c++
+
+ std::unique_ptr<vector> a;
+ int b = a[0];
+
+will generate a warning.
+
+STL containers for which ``operator[]`` is well-defined for all inputs are excluded
+from this check (e.g.: ``std::map::operator[]``).
+
+This check enforces part of the `SL.con.3
+<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#slcon3-avoid-bounds-errors>`
+guideline and is part of the `Bounds Safety (Bounds 4)
+<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Pro-bounds-arrayindex>`
+profile from the C++ Core Guidelines.
+
+Options
+-------
+
+.. option:: ExcludeClasses
+
+ Semicolon-delimited list of class names for overwriting the default
+ exclusion list. The default is:
+ `::std::map;::std::unordered_map;::std::flat_map`.
+
+.. option:: FixMode
+
+ Determines what fixes are suggested. Either `none`, `at` (use
+ ``a.at(index)`` if a fitting function exists) or `function` (use a
+ function ``f(a, index)``). The default is `none`.
+
+.. option:: FixFunction
+
+ The function to use in the `function` mode. For C++23 and beyond, the
+ passed function must support the empty subscript operator, i.e., the case
+ where ``a[]`` becomes ``f(a)``. :option:`FixFunctionEmptyArgs` can be
+ used to override the suggested function in that case. The default is `gsl::at`.
+
+.. option:: FixFunctionEmptyArgs
+
+ The function to use in the `function` mode for the empty subscript operator
+ case in C++23 and beyond only. If no fixes should be made for empty
+ subscript operators, pass an empty string. In that case, only the warnings
+ will be printed. The default is the value of :option:`FixFunction`.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-pointer-arithmetic.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-pointer-arithmetic.rst
index 12a8f60..a3f1371 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-pointer-arithmetic.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-bounds-pointer-arithmetic.rst
@@ -13,3 +13,11 @@ arrays of data.
This rule is part of the `Bounds safety (Bounds 1)
<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Pro-bounds-arithmetic>`_
profile from the C++ Core Guidelines.
+
+Options
+-------
+
+.. option:: AllowIncrementDecrementOperators
+
+ When enabled, the check will allow using the prefix/postfix increment or
+ decrement operators on pointers. Default is ``false``.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index b6444eb..5e3ffc4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -201,6 +201,7 @@ Clang-Tidy Checks
:doc:`cppcoreguidelines-owning-memory <cppcoreguidelines/owning-memory>`,
:doc:`cppcoreguidelines-prefer-member-initializer <cppcoreguidelines/prefer-member-initializer>`, "Yes"
:doc:`cppcoreguidelines-pro-bounds-array-to-pointer-decay <cppcoreguidelines/pro-bounds-array-to-pointer-decay>`,
+ :doc:`cppcoreguidelines-pro-bounds-avoid-unchecked-container-access <cppcoreguidelines/pro-bounds-avoid-unchecked-container-access>`, "Yes"
:doc:`cppcoreguidelines-pro-bounds-constant-array-index <cppcoreguidelines/pro-bounds-constant-array-index>`, "Yes"
:doc:`cppcoreguidelines-pro-bounds-pointer-arithmetic <cppcoreguidelines/pro-bounds-pointer-arithmetic>`,
:doc:`cppcoreguidelines-pro-type-const-cast <cppcoreguidelines/pro-type-const-cast>`,
@@ -271,6 +272,7 @@ Clang-Tidy Checks
:doc:`misc-no-recursion <misc/no-recursion>`,
:doc:`misc-non-copyable-objects <misc/non-copyable-objects>`,
:doc:`misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
+ :doc:`misc-override-with-different-visibility <misc/override-with-different-visibility>`,
:doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes"
:doc:`misc-static-assert <misc/static-assert>`, "Yes"
:doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/override-with-different-visibility.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/override-with-different-visibility.rst
new file mode 100644
index 0000000..310bfe2
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/override-with-different-visibility.rst
@@ -0,0 +1,87 @@
+.. title:: clang-tidy - misc-override-with-different-visibility
+
+misc-override-with-different-visibility
+=======================================
+
+Finds virtual function overrides with different visibility than the function
+in the base class. This includes for example if a virtual function declared as
+``private`` is overridden and declared as ``public`` in a subclass. The detected
+change is the modification of visibility resulting from keywords ``public``,
+``protected``, ``private`` at overridden virtual functions. The check applies to
+any normal virtual function and optionally to destructors or operators. Use of
+the ``using`` keyword is not considered as visibility change by this check.
+
+
+.. code-block:: c++
+
+ class A {
+ public:
+ virtual void f_pub();
+ private:
+ virtual void f_priv();
+ };
+
+ class B: public A {
+ public:
+ void f_priv(); // warning: changed visibility from private to public
+ private:
+ void f_pub(); // warning: changed visibility from public to private
+ };
+
+ class C: private A {
+ // no warning: f_pub becomes private in this case but this is from the
+ // private inheritance
+ };
+
+ class D: private A {
+ public:
+ void f_pub(); // warning: changed visibility from private to public
+ // 'f_pub' would have private access but is forced to be
+ // public
+ };
+
+If the visibility is changed in this way, it can indicate bad design or
+programming error.
+
+If a virtual function is private in a subclass but public in the base class, it
+can still be accessed from a pointer to the subclass if the pointer is converted
+to the base type. Probably private inheritance can be used instead.
+
+A protected virtual function that is made public in a subclass may have valid
+use cases but similar (not exactly same) effect can be achieved with the
+``using`` keyword.
+
+Options
+-------
+
+.. option:: DisallowedVisibilityChange
+
+ Controls what kind of change to the visibility will be detected by the check.
+ Possible values are `any`, `widening`, `narrowing`. For example the
+ `widening` option will produce warning only if the visibility is changed
+ from more restrictive (``private``) to less restrictive (``public``).
+ Default value is `any`.
+
+.. option:: CheckDestructors
+
+ If `true`, the check does apply to destructors too. Otherwise destructors
+ are ignored by the check.
+ Default value is `false`.
+
+.. option:: CheckOperators
+
+ If `true`, the check does apply to overloaded C++ operators (as virtual
+ member functions) too. This includes other special member functions (like
+ conversions) too. This option is probably useful only in rare cases because
+ operators and conversions are not often virtual functions.
+ Default value is `false`.
+
+.. option:: IgnoredFunctions
+
+ This option can be used to ignore the check at specific functions.
+ To configure this option, a semicolon-separated list of function names
+ should be provided. The list can contain regular expressions, in this way it
+ is possible to select all functions of a specific class (like `MyClass::.*`)
+ or a specific function of any class (like `my_function` or
+ `::.*::my_function`). The function names are matched at the base class.
+ Default value is empty string.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
index 8a54687..0e031a1 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
@@ -43,14 +43,21 @@ The options and their corresponding values are:
- ``LowerCase`` - example: ``int i_Variable``
- ``CamelCase`` - example: ``int IVariable``
-Options
--------
+Options summary
+---------------
-The following options are described below:
+The available options are summarized below:
+
+**General options**
- - :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
- :option:`AggressiveDependentMemberLookup`
- :option:`CheckAnonFieldInParent`
+ - :option:`GetConfigPerFile`
+ - :option:`IgnoreMainLikeFunctions`
+
+**Specific options**
+
+ - :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
@@ -66,13 +73,11 @@ The following options are described below:
- :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp`
- :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix`
- :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp`
- - :option:`GetConfigPerFile`
- :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix`
- :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix`
- :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp`
- :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix`
- :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix`
- - :option:`IgnoreMainLikeFunctions`
- :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp`
- :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix`
- :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix`
@@ -105,6 +110,12 @@ The following options are described below:
- :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix`
- :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp`
+
+Options description
+-------------------
+
+A detailed description of each option is presented below:
+
.. option:: AbstractClassCase
When defined, the check will ensure abstract class names conform to the
diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst
index b7a366e..3abd663 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -111,6 +111,13 @@ Diagnostics which have a corresponding warning option, are named
``-Wliteral-conversion`` will be reported with check name
``clang-diagnostic-literal-conversion``.
+Clang compiler errors (such as syntax errors, semantic errors, or other failures
+that prevent Clang from compiling the code) are reported with the check name
+``clang-diagnostic-error``. These represent fundamental compilation failures that
+must be fixed before :program:`clang-tidy` can perform its analysis. Unlike other
+diagnostics, ``clang-diagnostic-error`` cannot be disabled, as :program:`clang-tidy`
+requires valid code to function.
+
The ``-fix`` flag instructs :program:`clang-tidy` to fix found errors if
supported by corresponding checks.
@@ -213,14 +220,19 @@ An overview of all the command-line options:
Can be used together with -line-filter.
This option overrides the 'HeaderFilterRegex'
option in .clang-tidy file, if any.
- --line-filter=<string> - List of files with line ranges to filter the
- warnings. Can be used together with
- -header-filter. The format of the list is a
- JSON array of objects:
+ --line-filter=<string> - List of files and line ranges to output diagnostics from.
+ The range is inclusive on both ends. Can be used together
+ with -header-filter. The format of the list is a JSON
+ array of objects. For example:
+
[
{"name":"file1.cpp","lines":[[1,3],[5,7]]},
{"name":"file2.h"}
]
+
+ This will output diagnostics from 'file1.cpp' only for
+ the line ranges [1,3] and [5,7], as well as all from the
+ entire 'file2.h'.
--list-checks - List all enabled checks and exit. Use with
-checks=* to list all available checks.
--load=<pluginfilename> - Load the specified plugin
@@ -331,6 +343,107 @@ An overview of all the command-line options:
some-check.SomeOption: 'some value'
...
+Clang-Tidy Automation
+=====================
+
+:program:`clang-tidy` can analyze multiple source files by specifying them on
+the command line. For larger projects, automation scripts provide additional
+functionality like parallel execution and integration with version control
+systems.
+
+Running Clang-Tidy in Parallel
+-------------------------------
+
+:program:`clang-tidy` can process multiple files sequentially, but for projects
+with many source files, the :program:`run-clang-tidy.py` script provides
+parallel execution to significantly reduce analysis time. This script is
+included with clang-tidy and runs :program:`clang-tidy` over all files in a
+compilation database or a specified path concurrently.
+
+The script requires a compilation database (``compile_commands.json``) which
+can be generated by build systems like CMake (using
+``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON``) or by tools like `Bear`_.
+
+The script supports most of the same options as :program:`clang-tidy` itself,
+including ``-checks=``, ``-fix``, ``-header-filter=``, and configuration
+options. Run ``run-clang-tidy.py --help`` for a complete list of available
+options.
+
+Example invocations:
+
+.. code-block:: console
+
+ # Run clang-tidy on all files in the compilation database in parallel
+ $ run-clang-tidy.py -p=build/
+
+ # Run with specific checks and apply fixes
+ $ run-clang-tidy.py -p=build/ -fix -checks=-*,readability-*
+
+ # Run on specific files/directories with header filtering
+ $ run-clang-tidy.py -p=build/ -header-filter=src/ src/
+
+ # Run with parallel execution (uses all CPU cores by default)
+ $ run-clang-tidy.py -p=build/ -j 4
+
+Running Clang-Tidy on Diff
+---------------------------
+
+The :program:`clang-tidy-diff.py` script allows you to run
+:program:`clang-tidy` on the lines that have been modified in your working
+directory or in a specific diff. Importantly, :program:`clang-tidy-diff.py` only reports
+diagnostics for changed lines; :program:`clang-tidy` still analyzes the entire
+file and filters out unchanged lines after analysis, so this does not improve
+performance. This is particularly useful for code reviews and continuous
+integration, as it focuses analysis on the changed code rather than the entire
+codebase.
+
+The script can work with various diff sources:
+
+* Git working directory changes
+* Output from ``git diff``
+* Output from ``svn diff``
+* Patch files
+
+Example invocations:
+
+.. code-block:: console
+
+ # Run clang-tidy on all changes in the working directory
+ $ git diff -U0 --no-color HEAD^ | clang-tidy-diff.py -p1
+
+ # Run with specific checks and apply fixes
+ $ git diff -U0 --no-color HEAD^ | clang-tidy-diff.py -p1 -fix \
+ -checks=-*,readability-*
+
+ # Run on staged changes
+ $ git diff -U0 --no-color --cached | clang-tidy-diff.py -p1
+
+ # Run on changes between two commits
+ $ git diff -U0 --no-color HEAD~2 HEAD | clang-tidy-diff.py -p1
+
+ # Run on a patch file
+ $ clang-tidy-diff.py -p1 < changes.patch
+
+The ``-p1`` option tells the script to strip one level of path prefix from
+the diff, which is typically needed for Git diffs. The script supports most of
+the same options as :program:`clang-tidy` itself, including ``-checks=``,
+``-fix``, ``-header-filter=``, and configuration options.
+
+While :program:`clang-tidy-diff.py` is useful for focusing on recent changes,
+relying solely on it may lead to incomplete analysis. Since the script only
+reports warnings from the modified lines, it may miss issues that are caused
+by the changes but manifest elsewhere in the code. For example, changes that
+only add lines to a function may cause it to violate size limits (e.g.,
+`readability-function-size <checks/readability/function-size.html>`_), but the
+diagnostic will be reported at the function declaration, which may not be in
+the diff and thus filtered out. Modifications to header files may also affect
+many implementation files, but only warnings in the modified header lines will
+be reported.
+
+For comprehensive analysis, especially before merging significant changes,
+consider running :program:`clang-tidy` on the entire affected files or the
+whole project using :program:`run-clang-tidy.py`.
+
.. _clang-tidy-nolint:
Suppressing Undesired Diagnostics
@@ -453,5 +566,6 @@ example, ``NOLINTBEGIN(check-name)`` can be paired with
:program:`clang-tidy` will generate a ``clang-tidy-nolint`` error diagnostic if
any ``NOLINTBEGIN``/``NOLINTEND`` comment violates these requirements.
+.. _Bear: https://github.com/rizsotto/Bear
.. _LibTooling: https://clang.llvm.org/docs/LibTooling.html
.. _How To Setup Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
diff --git a/clang-tools-extra/docs/index.rst b/clang-tools-extra/docs/index.rst
index 9f7324f..3f3a99d 100644
--- a/clang-tools-extra/docs/index.rst
+++ b/clang-tools-extra/docs/index.rst
@@ -17,6 +17,7 @@ Contents
clang-tidy/index
clang-include-fixer
+ clang-change-namespace
modularize
pp-trace
clangd <https://clangd.llvm.org/>
diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
index 49cc136..0cbf9a0 100644
--- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -60,14 +60,10 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
NamedDecl *getMemberProvider(QualType Base) {
if (Base->isPointerType())
return getMemberProvider(Base->getPointeeType());
- // Unwrap the sugar ElaboratedType.
- if (const auto *ElTy = dyn_cast<ElaboratedType>(Base))
- return getMemberProvider(ElTy->getNamedType());
-
if (const auto *TT = dyn_cast<TypedefType>(Base))
return TT->getDecl();
if (const auto *UT = dyn_cast<UsingType>(Base))
- return UT->getFoundDecl();
+ return UT->getDecl();
// A heuristic: to resolve a template type to **only** its template name.
// We're only using this method for the base type of MemberExpr, in general
// the template provides the member, and the critical case `unique_ptr<Foo>`
@@ -135,16 +131,14 @@ public:
}
bool qualifierIsNamespaceOrNone(DeclRefExpr *DRE) {
- const auto *Qual = DRE->getQualifier();
- if (!Qual)
- return true;
- switch (Qual->getKind()) {
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::Global:
+ NestedNameSpecifier Qual = DRE->getQualifier();
+ switch (Qual.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Namespace:
+ case NestedNameSpecifier::Kind::Global:
return true;
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::Super:
- case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Kind::Type:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
return false;
}
llvm_unreachable("Unknown value for NestedNameSpecifierKind");
@@ -341,17 +335,17 @@ public:
}
bool VisitUsingTypeLoc(UsingTypeLoc TL) {
- reportType(TL.getNameLoc(), TL.getFoundDecl());
+ reportType(TL.getNameLoc(), TL.getDecl());
return true;
}
bool VisitTagTypeLoc(TagTypeLoc TTL) {
- reportType(TTL.getNameLoc(), TTL.getDecl());
+ reportType(TTL.getNameLoc(), TTL.getOriginalDecl());
return true;
}
bool VisitTypedefTypeLoc(TypedefTypeLoc TTL) {
- reportType(TTL.getNameLoc(), TTL.getTypedefNameDecl());
+ reportType(TTL.getNameLoc(), TTL.getDecl());
return true;
}
diff --git a/clang-tools-extra/test/clang-doc/basic-project.mustache.test b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
index e2d9da6..5509951 100644
--- a/clang-tools-extra/test/clang-doc/basic-project.mustache.test
+++ b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
@@ -2,10 +2,10 @@
// RUN: sed 's|$test_dir|%/S|g' %S/Inputs/basic-project/database_template.json > %t/build/compile_commands.json
// RUN: clang-doc --format=mustache --output=%t/docs --executor=all-TUs %t/build/compile_commands.json
-// RUN: FileCheck %s -input-file=%t/docs/_ZTV5Shape.html -check-prefix=HTML-SHAPE
-// RUN: FileCheck %s -input-file=%t/docs/_ZTV10Calculator.html -check-prefix=HTML-CALC
-// RUN: FileCheck %s -input-file=%t/docs/_ZTV9Rectangle.html -check-prefix=HTML-RECTANGLE
-// RUN: FileCheck %s -input-file=%t/docs/_ZTV6Circle.html -check-prefix=HTML-CIRCLE
+// RUN: FileCheck %s -input-file=%t/docs/html/_ZTV5Shape.html -check-prefix=HTML-SHAPE
+// RUN: FileCheck %s -input-file=%t/docs/html/_ZTV10Calculator.html -check-prefix=HTML-CALC
+// RUN: FileCheck %s -input-file=%t/docs/html/_ZTV9Rectangle.html -check-prefix=HTML-RECTANGLE
+// RUN: FileCheck %s -input-file=%t/docs/html/_ZTV6Circle.html -check-prefix=HTML-CIRCLE
HTML-SHAPE: <html lang="en-US">
HTML-SHAPE: <head>
diff --git a/clang-tools-extra/test/clang-doc/json/class-requires.cpp b/clang-tools-extra/test/clang-doc/json/class-requires.cpp
index bf6c889..5139617 100644
--- a/clang-tools-extra/test/clang-doc/json/class-requires.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class-requires.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/_ZTV7MyClass.json
+// RUN: FileCheck %s < %t/json/_ZTV7MyClass.json
template<typename T>
concept Addable = requires(T a, T b) {
diff --git a/clang-tools-extra/test/clang-doc/json/class-specialization.cpp b/clang-tools-extra/test/clang-doc/json/class-specialization.cpp
index e9259ed..d3ad695 100644
--- a/clang-tools-extra/test/clang-doc/json/class-specialization.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class-specialization.cpp
@@ -1,7 +1,7 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/_ZTV7MyClass.json --check-prefix=BASE
-// RUN: FileCheck %s < %t/_ZTV7MyClassIiE.json --check-prefix=SPECIALIZATION
+// RUN: FileCheck %s < %t/json/_ZTV7MyClass.json --check-prefix=BASE
+// RUN: FileCheck %s < %t/json/_ZTV7MyClassIiE.json --check-prefix=SPECIALIZATION
template<typename T> struct MyClass {};
diff --git a/clang-tools-extra/test/clang-doc/json/class-template.cpp b/clang-tools-extra/test/clang-doc/json/class-template.cpp
index 149248c..5ef78f54 100644
--- a/clang-tools-extra/test/clang-doc/json/class-template.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class-template.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/_ZTV7MyClass.json
+// RUN: FileCheck %s < %t/json/_ZTV7MyClass.json
template<typename T> struct MyClass {
T MemberTemplate;
diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp
index 79b8fed..20a9f21 100644
--- a/clang-tools-extra/test/clang-doc/json/class.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/_ZTV7MyClass.json
+// RUN: FileCheck %s < %t/json/_ZTV7MyClass.json
struct Foo;
diff --git a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
index bb2b4ca..1a73a0d 100644
--- a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
+++ b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/index.json
+// RUN: FileCheck %s < %t/json/index.json
template<typename T> concept Incrementable = requires (T a) {
a++;
diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp b/clang-tools-extra/test/clang-doc/json/concept.cpp
index 4c81024..e96ec14 100644
--- a/clang-tools-extra/test/clang-doc/json/concept.cpp
+++ b/clang-tools-extra/test/clang-doc/json/concept.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/index.json
+// RUN: FileCheck %s < %t/json/index.json
// Requires that T suports post and pre-incrementing.
template<typename T>
diff --git a/clang-tools-extra/test/clang-doc/json/function-requires.cpp b/clang-tools-extra/test/clang-doc/json/function-requires.cpp
index 59ed39e..9427146 100644
--- a/clang-tools-extra/test/clang-doc/json/function-requires.cpp
+++ b/clang-tools-extra/test/clang-doc/json/function-requires.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/index.json
+// RUN: FileCheck %s < %t/json/index.json
template<typename T>
concept Incrementable = requires(T x) {
diff --git a/clang-tools-extra/test/clang-doc/json/function-specifiers.cpp b/clang-tools-extra/test/clang-doc/json/function-specifiers.cpp
index b194e33..faaccb7 100644
--- a/clang-tools-extra/test/clang-doc/json/function-specifiers.cpp
+++ b/clang-tools-extra/test/clang-doc/json/function-specifiers.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/index.json
+// RUN: FileCheck %s < %t/json/index.json
static void myFunction() {}
diff --git a/clang-tools-extra/test/clang-doc/json/method-template.cpp b/clang-tools-extra/test/clang-doc/json/method-template.cpp
index 14232d0..87977f8 100644
--- a/clang-tools-extra/test/clang-doc/json/method-template.cpp
+++ b/clang-tools-extra/test/clang-doc/json/method-template.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/_ZTV7MyClass.json
+// RUN: FileCheck %s < %t/json/_ZTV7MyClass.json
struct MyClass {
template<class T> T methodTemplate(T param) {
diff --git a/clang-tools-extra/test/clang-doc/json/namespace.cpp b/clang-tools-extra/test/clang-doc/json/namespace.cpp
index 4b6b388..dcf8323 100644
--- a/clang-tools-extra/test/clang-doc/json/namespace.cpp
+++ b/clang-tools-extra/test/clang-doc/json/namespace.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/index.json
+// RUN: FileCheck %s < %t/json/index.json
class MyClass {};
diff --git a/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp b/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp
index 255e540..b19afc1 100644
--- a/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp
+++ b/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp
@@ -1,7 +1,7 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
-// RUN: FileCheck %s < %t/nested.json --check-prefix=NESTED
-// RUN: FileCheck %s < %t/inner.json --check-prefix=INNER
+// RUN: FileCheck %s < %t/json/nested.json --check-prefix=NESTED
+// RUN: FileCheck %s < %t/json/inner.json --check-prefix=INNER
namespace nested {
int Global;
diff --git a/clang-tools-extra/test/clang-doc/long-name.cpp b/clang-tools-extra/test/clang-doc/long-name.cpp
new file mode 100644
index 0000000..b333375
--- /dev/null
+++ b/clang-tools-extra/test/clang-doc/long-name.cpp
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: clang-doc --output=%t --format=mustache --executor=standalone %s
+// RUN: ls %t/json | FileCheck %s -check-prefix=CHECK-JSON
+// RUN: ls %t/html | FileCheck %s -check-prefix=CHECK-HTML
+
+struct ThisStructHasANameThatResultsInAMangledNameThatIsExactly250CharactersLongThatIsSupposedToTestTheFilenameLengthLimitsWithinClangDocInOrdertoSeeifclangdocwillcrashornotdependingonthelengthofthestructIfTheLengthIsTooLongThenClangDocWillCrashAnd12 {};
+
+// This name is 1 character over the limit, so it will be serialized as a USR.
+struct ThisStructHasANameThatResultsInAMangledNameThatIsExactly251CharactersLongThatIsSupposedToTestTheFilenameLengthLimitsWithinClangDocInOrdertoSeeifclangdocwillcrashornotdependingonthelengthofthestructIfTheLengthIsTooLongThenClangDocWillCrashAnd123 {};
+
+// CHECK-JSON: ThisStructHasANameThatResultsInAMangledNameThatIsExactly250CharactersLongThatIsSupposedToTestTheFilenameLengthLimitsWithinClangDocInOrdertoSeeifclangdocwillcrashornotdependingonthelengthofthestructIfTheLengthIsTooLongThenClangDocWillCrashAnd12.json
+// CHECK-JSON: {{[0-9A-F]*}}.json
+// CHECK-HTML: ThisStructHasANameThatResultsInAMangledNameThatIsExactly250CharactersLongThatIsSupposedToTestTheFilenameLengthLimitsWithinClangDocInOrdertoSeeifclangdocwillcrashornotdependingonthelengthofthestructIfTheLengthIsTooLongThenClangDocWillCrashAnd12.html
+// CHECK-HTML: {{[0-9A-F]*}}.html
diff --git a/clang-tools-extra/test/clang-doc/mustache-index.cpp b/clang-tools-extra/test/clang-doc/mustache-index.cpp
index 910233b..f9aad19 100644
--- a/clang-tools-extra/test/clang-doc/mustache-index.cpp
+++ b/clang-tools-extra/test/clang-doc/mustache-index.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --format=mustache --output=%t --executor=standalone %s
-// RUN: FileCheck %s < %t/index.html
+// RUN: FileCheck %s < %t/html/index.html
enum Color {
RED,
diff --git a/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp b/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp
index 7d7d108..a73a5ab 100644
--- a/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp
+++ b/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: clang-doc --format=mustache --output=%t --executor=standalone %s
-// RUN: FileCheck %s < %t/MyNamespace.html
+// RUN: FileCheck %s < %t/html/MyNamespace.html
namespace MyNamespace {
class Foo;
diff --git a/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.c b/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.c
new file mode 100644
index 0000000..7b531d9
--- /dev/null
+++ b/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.c
@@ -0,0 +1,12 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order z,y,x %s -- | FileCheck %s
+
+struct Foo {
+ int x; // CHECK: {{^ int z;}}
+ int y; // CHECK-NEXT: {{^ int y;}}
+ int z; // CHECK-NEXT: {{^ int x;}}
+};
+
+int main() {
+ struct Foo foo = { 0, 1 }; // CHECK: {{^ struct Foo foo = { .y = 1, .x = 0 };}}
+ return 0;
+}
diff --git a/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp b/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp
index 9d09c81..cda5f56 100644
--- a/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp
+++ b/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp
@@ -1,4 +1,5 @@
-// RUN: clang-reorder-fields -record-name Foo -fields-order z,y,x %s -- | FileCheck %s
+// RUN: clang-reorder-fields --extra-arg="-std=c++17" -record-name Foo -fields-order z,y,x %s -- 2>&1 | FileCheck --check-prefix=CHECK-MESSAGES %s
+// RUN: clang-reorder-fields --extra-arg="-std=c++17" -record-name Foo -fields-order z,y,x %s -- | FileCheck %s
// The order of fields should not change.
class Foo {
@@ -9,6 +10,7 @@ public:
};
int main() {
+ // CHECK-MESSAGES: :[[@LINE+1]]:13: Only full initialization without implicit values is supported
Foo foo = { 0, 1 }; // CHECK: {{^ Foo foo = { 0, 1 };}}
return 0;
}
diff --git a/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c b/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
new file mode 100644
index 0000000..c05c296
--- /dev/null
+++ b/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
@@ -0,0 +1,31 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order z,w,y,x %s -- | FileCheck %s
+
+struct Foo {
+ const int* x; // CHECK: {{^ double z;}}
+ int y; // CHECK-NEXT: {{^ int w;}}
+ double z; // CHECK-NEXT: {{^ int y;}}
+ int w; // CHECK-NEXT: {{^ const int\* x}}
+};
+
+struct Bar {
+ char a;
+ struct Foo b;
+ char c;
+};
+
+int main() {
+ const int x = 13;
+ struct Foo foo1 = { .x=&x, .y=0, .z=1.29, .w=17 }; // CHECK: {{^ struct Foo foo1 = { .z = 1.29, .w = 17, .y = 0, .x = &x };}}
+ struct Foo foo2 = { .x=&x, 0, 1.29, 17 }; // CHECK: {{^ struct Foo foo2 = { .z = 1.29, .w = 17, .y = 0, .x = &x };}}
+ struct Foo foo3 = { .y=0, .z=1.29, 17, .x=&x }; // CHECK: {{^ struct Foo foo3 = { .z = 1.29, .w = 17, .y = 0, .x = &x };}}
+ struct Foo foo4 = { .y=0, .z=1.29, 17 }; // CHECK: {{^ struct Foo foo4 = { .z = 1.29, .w = 17, .y = 0 };}}
+
+ struct Foo foos1[1] = { [0] = {.x=&x, 0, 1.29, 17} }; // CHECK: {{^ struct Foo foos1\[1] = { \[0] = {.z = 1.29, .w = 17, .y = 0, .x = &x} };}}
+ struct Foo foos2[1] = { [0].x=&x, [0].y=0, [0].z=1.29, [0].w=17 }; // CHECK: {{^ struct Foo foos2\[1] = { \[0].z = 1.29, \[0].w = 17, \[0].y = 0, \[0].x = &x };}}
+ struct Foo foos3[1] = { &x, 0, 1.29, 17 }; // CHECK: {{^ struct Foo foos3\[1] = { \[0].z = 1.29, \[0].w = 17, \[0].y = 0, \[0].x = &x };}}
+ struct Foo foos4[2] = { &x, 0, 1.29, 17, &x, 0, 1.29, 17 }; // CHECK: {{^ struct Foo foos4\[2] = { \[0].z = 1.29, \[0].w = 17, \[0].y = 0, \[0].x = &x, \[1].z = 1.29, \[1].w = 17, \[1].y = 0, \[1].x = &x };}}
+
+ struct Bar bar1 = { .a='a', &x, 0, 1.29, 17, 'c' }; // CHECK: {{^ struct Bar bar1 = { .a = 'a', .b.z = 1.29, .b.w = 17, .b.y = 0, .b.x = &x, .c = 'c' };}}
+
+ return 0;
+}
diff --git a/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.cpp b/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.cpp
new file mode 100644
index 0000000..15dac77
--- /dev/null
+++ b/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-reorder-fields --extra-arg="-std=c++20" -record-name Bar -fields-order c,a,b %s -- | FileCheck %s
+
+class Foo {
+public:
+ const int* x;
+ int y;
+};
+
+class Bar {
+public:
+ char a; // CHECK: {{^ int c;}}
+ Foo b; // CHECK-NEXT: {{^ char a;}}
+ int c; // CHECK-NEXT: {{^ Foo b;}}
+};
+
+int main() {
+ const int x = 13;
+ Bar bar1 = { 'a', { &x, 0 }, 123 }; // CHECK: {{^ Bar bar1 = { 123, 'a', { &x, 0 } };}}
+ Bar bar2 = { .a = 'a', { &x, 0 }, 123 }; // CHECK: {{^ Bar bar2 = { .c = 123, .a = 'a', .b = { &x, 0 } };}}
+ Bar bar3 = { 'a', .b { &x, 0 }, 123 }; // CHECK: {{^ Bar bar3 = { .c = 123, .a = 'a', .b = { &x, 0 } };}}
+ Bar bar4 = { .c = 123, .b { &x, 0 }, .a = 'a' }; // CHECK: {{^ Bar bar4 = { .c = 123, .a = 'a', .b = { &x, 0 } };}}
+
+ return 0;
+}
diff --git a/clang-tools-extra/test/clang-reorder-fields/IdiomaticZeroInitializer.c b/clang-tools-extra/test/clang-reorder-fields/IdiomaticZeroInitializer.c
new file mode 100644
index 0000000..59c12e81
--- /dev/null
+++ b/clang-tools-extra/test/clang-reorder-fields/IdiomaticZeroInitializer.c
@@ -0,0 +1,14 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order y,x %s -- | FileCheck %s
+
+struct Foo {
+ int x; // CHECK: {{^ int y;}}
+ int y; // CHECK-NEXT: {{^ int x;}}
+};
+
+int main() {
+ // The idiomatic zero initializer should remain the same.
+ struct Foo foo0 = { 0 }; // CHECK: {{^ struct Foo foo0 = { 0 };}}
+ struct Foo foo1 = { 1 }; // CHECK: {{^ struct Foo foo1 = { .x = 1 };}}
+
+ return 0;
+}
diff --git a/clang-tools-extra/test/clang-reorder-fields/InitializerListExcessElements.c b/clang-tools-extra/test/clang-reorder-fields/InitializerListExcessElements.c
new file mode 100644
index 0000000..b626e84
--- /dev/null
+++ b/clang-tools-extra/test/clang-reorder-fields/InitializerListExcessElements.c
@@ -0,0 +1,15 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order y,x %s -- 2>&1 | FileCheck --check-prefix=CHECK-MESSAGES %s
+// RUN: clang-reorder-fields -record-name Foo -fields-order y,x %s -- | FileCheck %s
+
+// The order of fields should not change.
+struct Foo {
+ int x; // CHECK: {{^ int x;}}
+ int y; // CHECK-NEXT: {{^ int y;}}
+};
+
+int main() {
+ // CHECK-MESSAGES: :[[@LINE+1]]:20: Unsupported initializer list
+ struct Foo foo = { .y=9, 123, .x=1 }; // CHECK: {{^ struct Foo foo = { .y=9, 123, .x=1 };}}
+
+ return 0;
+}
diff --git a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
index 774bc97..d80a280 100755
--- a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -45,6 +45,7 @@ Notes
import argparse
import os
import pathlib
+import platform
import re
import subprocess
import sys
@@ -135,8 +136,7 @@ class CheckRunner:
"-fblocks",
] + self.clang_extra_args
- if extension in [".cpp", ".hpp", ".mm"]:
- self.clang_extra_args.append("-std=" + self.std)
+ self.clang_extra_args.append("-std=" + self.std)
# Tests should not rely on STL being available, and instead provide mock
# implementations of relevant APIs.
@@ -146,7 +146,12 @@ class CheckRunner:
self.clang_extra_args.append("-resource-dir=%s" % self.resource_dir)
def read_input(self) -> None:
- with open(self.input_file_name, "r", encoding="utf-8") as input_file:
+ # Use a "\\?\" prefix on Windows to handle long file paths transparently:
+ # https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
+ file_name = self.input_file_name
+ if platform.system() == "Windows":
+ file_name = "\\\\?\\" + os.path.abspath(file_name)
+ with open(file_name, "r", encoding="utf-8") as input_file:
self.input_text = input_file.read()
def get_prefixes(self) -> None:
@@ -374,7 +379,7 @@ def parse_arguments() -> Tuple[argparse.Namespace, List[str]]:
parser.add_argument(
"-std",
type=csv,
- default=["c++11-or-later"],
+ default=None,
help="Passed to clang. Special -or-later values are expanded.",
)
parser.add_argument(
@@ -382,7 +387,15 @@ def parse_arguments() -> Tuple[argparse.Namespace, List[str]]:
action="store_true",
help="allow partial line matches for fixes",
)
- return parser.parse_known_args()
+
+ args, extra_args = parser.parse_known_args()
+ if args.std is None:
+ _, extension = os.path.splitext(args.assume_filename or args.input_file_name)
+ args.std = [
+ "c++11-or-later" if extension in [".cpp", ".hpp", ".mm"] else "c99-or-later"
+ ]
+
+ return (args, extra_args)
def main() -> None:
diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/stdfloat b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/stdfloat
new file mode 100644
index 0000000..c178e61
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/stdfloat
@@ -0,0 +1,18 @@
+//===--- stdfloat - Stub header for tests -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _STDFLOAT_
+#define _STDFLOAT_
+
+namespace std {
+
+// TODO: define std::float16_t and friends
+
+}
+
+#endif // _STDFLOAT_
diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/system-other.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/system-other.h
index 28c26b7..011c869 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/system-other.h
+++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/system-other.h
@@ -11,6 +11,8 @@
// Special system calls.
+#if __STDC_VERSION__ < 202311L
void other_call();
+#endif
#endif // _SYSTEM_OTHER_H_
diff --git a/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry-custom-macro.c b/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry-custom-macro.c
index 56c382c..3f60860 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry-custom-macro.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry-custom-macro.c
@@ -2,7 +2,7 @@
#define MY_TEMP_FAILURE_RETRY(x) \
({ \
- typeof(x) __z; \
+ __typeof__(x) __z; \
do \
__z = (x); \
while (__z == -1); \
@@ -11,7 +11,7 @@
#define MY_OTHER_TEMP_FAILURE_RETRY(x) \
({ \
- typeof(x) __z; \
+ __typeof__(x) __z; \
do \
__z = (x); \
while (__z == -1); \
diff --git a/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry.c b/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry.c
index 461fb4a..1c71ebb 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/android/comparison-in-temp-failure-retry.c
@@ -2,7 +2,7 @@
#define TEMP_FAILURE_RETRY(x) \
({ \
- typeof(x) __z; \
+ __typeof__(x) __z; \
do \
__z = (x); \
while (__z == -1); \
@@ -130,7 +130,7 @@ void obscured_temp_failure_retry(void) {
#undef TEMP_FAILURE_RETRY
#define IMPL(x) \
({ \
- typeof(x) __z; \
+ __typeof__(x) __z; \
do \
__z = (x); \
while (__z == -1); \
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-macro-crash.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-macro-crash.c
index a4cb734..0f4389c8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-macro-crash.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-macro-crash.c
@@ -1,11 +1,11 @@
// RUN: %check_clang_tidy %s bugprone-branch-clone %t
int x = 0;
int y = 1;
-#define a(b, c) \
- typeof(b) d; \
- if (b) \
- d = b; \
- else if (c) \
+#define a(b, c) \
+ __typeof__(b) d; \
+ if (b) \
+ d = b; \
+ else if (c) \
d = b;
void f(void) {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp
index b42d3fc..35314d1 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp
@@ -165,7 +165,6 @@ FROMMACRO
class X15 : public CopyableAlias2 {
X15(const X15 &other) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
- // CHECK-FIXES: X15(const X15 &other) : Copyable5(other) {}
};
class X16 : public NonCopyable {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-relatedness.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-relatedness.c
index 7231361..45752de 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-relatedness.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-relatedness.c
@@ -1,4 +1,15 @@
-// RUN: %check_clang_tidy %s bugprone-easily-swappable-parameters %t \
+// RUN: %check_clang_tidy -std=c99,c11,c17 -check-suffixes=,BEFORE-C23 %s bugprone-easily-swappable-parameters %t \
+// RUN: -config='{CheckOptions: { \
+// RUN: bugprone-easily-swappable-parameters.MinimumLength: 2, \
+// RUN: bugprone-easily-swappable-parameters.IgnoredParameterNames: "", \
+// RUN: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes: "", \
+// RUN: bugprone-easily-swappable-parameters.QualifiersMix: 0, \
+// RUN: bugprone-easily-swappable-parameters.ModelImplicitConversions: 0, \
+// RUN: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether: 1, \
+// RUN: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold: 0 \
+// RUN: }}' -- -Wno-strict-prototypes -x c
+//
+// RUN: %check_clang_tidy -std=c23-or-later %s bugprone-easily-swappable-parameters %t \
// RUN: -config='{CheckOptions: { \
// RUN: bugprone-easily-swappable-parameters.MinimumLength: 2, \
// RUN: bugprone-easily-swappable-parameters.IgnoredParameterNames: "", \
@@ -9,7 +20,6 @@
// RUN: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold: 0 \
// RUN: }}' -- -Wno-strict-prototypes -x c
-int myprint();
int add(int X, int Y);
void notRelated(int A, int B) {}
@@ -19,13 +29,18 @@ void notRelated(int A, int B) {}
int addedTogether(int A, int B) { return add(A, B); } // NO-WARN: Passed to same function.
+#if __STDC_VERSION__ < 202311L
+int myprint();
void passedToSameKNRFunction(int A, int B) {
myprint("foo", A);
myprint("bar", B);
}
-// CHECK-MESSAGES: :[[@LINE-4]]:30: warning: 2 adjacent parameters of 'passedToSameKNRFunction' of similar type ('int')
-// CHECK-MESSAGES: :[[@LINE-5]]:34: note: the first parameter in the range is 'A'
-// CHECK-MESSAGES: :[[@LINE-6]]:41: note: the last parameter in the range is 'B'
-// This is actually a false positive: the "passed to same function" heuristic
+// CHECK-MESSAGES-BEFORE-C23: :[[@LINE-4]]:30: warning: 2 adjacent parameters of 'passedToSameKNRFunction' of similar type ('int')
+// CHECK-MESSAGES-BEFORE-C23: :[[@LINE-5]]:34: note: the first parameter in the range is 'A'
+// CHECK-MESSAGES-BEFORE-C23: :[[@LINE-6]]:41: note: the last parameter in the range is 'B'
+// FIXME: This is actually a false positive: the "passed to same function" heuristic
// can't map the parameter index 1 to A and B because myprint() has no
// parameters.
+// If you fix this, you should be able to combine the `%check_clang_tidy` invocations
+// in this file into one and remove the `-std` and `-check-suffixes` arguments.
+#endif
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters.c
index b6c9bf4..be44cfc 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters.c
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-easily-swappable-parameters %t \
+// RUN: %check_clang_tidy -std=c99,c11,c17 -check-suffixes=,BEFORE-23 %s bugprone-easily-swappable-parameters %t \
// RUN: -config='{CheckOptions: { \
// RUN: bugprone-easily-swappable-parameters.MinimumLength: 2, \
// RUN: bugprone-easily-swappable-parameters.IgnoredParameterNames: "", \
@@ -7,7 +7,18 @@
// RUN: bugprone-easily-swappable-parameters.ModelImplicitConversions: 0, \
// RUN: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether: 0, \
// RUN: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold: 0 \
-// RUN: }}' -- -Wno-strict-prototypes -x c
+// RUN: }}' -- -Wno-strict-prototypes
+//
+// RUN: %check_clang_tidy -std=c23-or-later %s bugprone-easily-swappable-parameters %t \
+// RUN: -config='{CheckOptions: { \
+// RUN: bugprone-easily-swappable-parameters.MinimumLength: 2, \
+// RUN: bugprone-easily-swappable-parameters.IgnoredParameterNames: "", \
+// RUN: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes: "bool;MyBool;struct U;MAKE_LOGICAL_TYPE(int)", \
+// RUN: bugprone-easily-swappable-parameters.QualifiersMix: 0, \
+// RUN: bugprone-easily-swappable-parameters.ModelImplicitConversions: 0, \
+// RUN: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether: 0, \
+// RUN: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold: 0 \
+// RUN: }}' -- -Wno-strict-prototypes
#define bool _Bool
#define true 1
@@ -45,8 +56,11 @@ void pointerConversion(int *IP, long *LP) {}
void testVariadicsCall() {
int IVal = 1;
+
+#if __STDC_VERSION__ < 202311L
decl(IVal); // NO-WARN: Particular calls to "variadics" are like template
// instantiations, and we do not model them.
+#endif
variadic(IVal); // NO-WARN.
variadic(IVal, 2, 3, 4); // NO-WARN.
@@ -64,13 +78,15 @@ void taggedTypes2(struct S SVar1, struct S SVar2) {}
void wrappers(struct { int I; } I1, struct { int I; } I2) {} // NO-WARN: Distinct anonymous types.
+#if __STDC_VERSION__ < 202311L
void knr(I, J)
int I;
int J;
{}
-// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: 2 adjacent parameters of 'knr' of similar type ('int')
-// CHECK-MESSAGES: :[[@LINE-4]]:7: note: the first parameter in the range is 'I'
-// CHECK-MESSAGES: :[[@LINE-4]]:7: note: the last parameter in the range is 'J'
+// CHECK-MESSAGES-BEFORE-23: :[[@LINE-3]]:3: warning: 2 adjacent parameters of 'knr' of similar type ('int')
+// CHECK-MESSAGES-BEFORE-23: :[[@LINE-4]]:7: note: the first parameter in the range is 'I'
+// CHECK-MESSAGES-BEFORE-23: :[[@LINE-4]]:7: note: the last parameter in the range is 'J'
+#endif
void boolAsWritten(bool B1, bool B2) {} // NO-WARN: The type name is ignored.
// Note that "bool" is a macro that expands to "_Bool" internally, but it is
@@ -145,7 +161,7 @@ void thisIsGettingRidiculous(MAKE_PRIMITIVE_WRAPPER(int) I1,
void macroMagic3(MAKE_LOGICAL_TYPE(char) B1, MAKE_LOGICAL_TYPE(long) B2) {}
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 2 adjacent parameters of 'macroMagic3' of similar type ('bool')
// CHECK-MESSAGES: :[[@LINE-4]]:30: note: expanded from macro 'MAKE_LOGICAL_TYPE'
-// CHECK-MESSAGES: :[[@LINE-136]]:14: note: expanded from macro 'bool'
+// CHECK-MESSAGES: :[[@LINE-141]]:14: note: expanded from macro 'bool'
// CHECK-MESSAGES: :[[@LINE-4]]:42: note: the first parameter in the range is 'B1'
// CHECK-MESSAGES: :[[@LINE-5]]:70: note: the last parameter in the range is 'B2'
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-in-initialization-strlen.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-in-initialization-strlen.c
index a383958..b241d68 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-in-initialization-strlen.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-in-initialization-strlen.c
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy --match-partial-fixes %s bugprone-not-null-terminated-result %t -- \
-// RUN: -- -std=c11 -I %S/Inputs/not-null-terminated-result
+// RUN: -- -I %S/Inputs/not-null-terminated-result
#include "not-null-terminated-result-c.h"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-before-safe.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-before-safe.c
index 434cfcc..ea7e183 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-before-safe.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-before-safe.c
@@ -1,7 +1,7 @@
// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \
// RUN: -config="{CheckOptions: \
// RUN: {bugprone-not-null-terminated-result.WantToUseSafeFunction: true}}" \
-// RUN: -- -std=c11 -I %S/Inputs/not-null-terminated-result
+// RUN: -- -I %S/Inputs/not-null-terminated-result
#include "not-null-terminated-result-c.h"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-safe.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-safe.c
index 5a5e35e..ae43087 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-safe.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-memcpy-safe.c
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \
-// RUN: -- -std=c11 -I %S/Inputs/not-null-terminated-result
+// RUN: -- -I %S/Inputs/not-null-terminated-result
#include "not-null-terminated-result-c.h"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-stdc-want-lib-ext1-not-a-literal.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-stdc-want-lib-ext1-not-a-literal.c
index 0628d0ca..9480671 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-stdc-want-lib-ext1-not-a-literal.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-stdc-want-lib-ext1-not-a-literal.c
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \
-// RUN: -- -std=c11 -I %S/Inputs/not-null-terminated-result
+// RUN: -- -I %S/Inputs/not-null-terminated-result
#include "not-null-terminated-result-c.h"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-strlen.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-strlen.c
index 4970af8..366c169 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-strlen.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-strlen.c
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy --match-partial-fixes %s bugprone-not-null-terminated-result %t -- \
-// RUN: -- -std=c11 -I %S/Inputs/not-null-terminated-result
+// RUN: -- -I %S/Inputs/not-null-terminated-result
// FIXME: Something wrong with the APInt un/signed conversion on Windows:
// in 'strncmp(str6, "string", 7);' it tries to inject '4294967302' as length.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-undef-stdc-want-lib-ext1.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-undef-stdc-want-lib-ext1.c
index 2704dc1..bb5961f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-undef-stdc-want-lib-ext1.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/not-null-terminated-result-undef-stdc-want-lib-ext1.c
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \
-// RUN: -- -std=c11 -I %S/Inputs/not-null-terminated-result
+// RUN: -- -I %S/Inputs/not-null-terminated-result
#include "not-null-terminated-result-c.h"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.c
index c7daec0..a8f6f3b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.c
@@ -1,4 +1,5 @@
-// RUN: %check_clang_tidy %s bugprone-signal-handler %t -- -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy -std=c99,c11,c17 -check-suffixes=,BEFORE-23 %s bugprone-signal-handler %t -- -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy -std=c23-or-later %s bugprone-signal-handler %t -- -- -isystem %clang_tidy_headers
#include "signal.h"
#include "stdlib.h"
@@ -174,8 +175,10 @@ void test_other(void) {
signal(SIGINT, handler_signal);
signal(SIGINT, _Exit);
+#if __STDC_VERSION__ < 202311L
signal(SIGINT, other_call);
- // CHECK-NOTES: :[[@LINE-1]]:18: warning: standard function 'other_call' may not be asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
+ // CHECK-NOTES-BEFORE-23: :[[@LINE-1]]:18: warning: standard function 'other_call' may not be asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
+#endif
signal(SIGINT, f_extern_handler);
// CHECK-NOTES: :[[@LINE-1]]:18: warning: cannot verify that external function 'f_extern_handler' is asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c
index ad6e31d..cd66511 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-signed-char-misuse %t -- -- -std=c23
+// RUN: %check_clang_tidy -std=c23-or-later %s bugprone-signed-char-misuse %t
///////////////////////////////////////////////////////////////////
/// Test cases correctly caught by the check.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.c
index b898071..871715b2 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.c
@@ -1,5 +1,5 @@
-// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- --
-// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- -- -x c++
+// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-sizeof-expression %t -- -- -x c++
#ifdef __cplusplus
#define STRKWD
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
index 3167b85..4911157 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
@@ -141,6 +141,17 @@ void nullable_value_after_swap(BloombergLP::bdlb::NullableValue<int> &opt1, Bloo
}
}
+void assertion_handler() __attribute__((analyzer_noreturn));
+
+void function_calling_analyzer_noreturn(const bsl::optional<int>& opt)
+{
+ if (!opt) {
+ assertion_handler();
+ }
+
+ *opt; // no-warning: The previous condition guards this dereference.
+}
+
template <typename T>
void function_template_without_user(const absl::optional<T> &opt) {
opt.value(); // no-warning
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c
index 0409dd6..452e229 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c
@@ -5,14 +5,14 @@
// parsing and preprocessor state will not have that case.
// UNSUPPORTED: target={{.*-(ps4|ps5)}}
//
-// RUN: %check_clang_tidy -check-suffix=WITH-ANNEX-K %s bugprone-unsafe-functions %t -- -- -D__STDC_LIB_EXT1__=1 -D__STDC_WANT_LIB_EXT1__=1
-// RUN: %check_clang_tidy -check-suffix=WITHOUT-ANNEX-K %s bugprone-unsafe-functions %t -- -- -U__STDC_LIB_EXT1__ -U__STDC_WANT_LIB_EXT1__
-// RUN: %check_clang_tidy -check-suffix=WITHOUT-ANNEX-K %s bugprone-unsafe-functions %t -- -- -D__STDC_LIB_EXT1__=1 -U__STDC_WANT_LIB_EXT1__
-// RUN: %check_clang_tidy -check-suffix=WITHOUT-ANNEX-K %s bugprone-unsafe-functions %t -- -- -U__STDC_LIB_EXT1__ -D__STDC_WANT_LIB_EXT1__=1
-// RUN: %check_clang_tidy -check-suffix=WITH-ANNEX-K-CERT-ONLY %s bugprone-unsafe-functions %t -- \
+// RUN: %check_clang_tidy -std=c11-or-later -check-suffix=WITH-ANNEX-K %s bugprone-unsafe-functions %t -- -- -D__STDC_LIB_EXT1__=1 -D__STDC_WANT_LIB_EXT1__=1
+// RUN: %check_clang_tidy -check-suffix=WITHOUT-ANNEX-K %s bugprone-unsafe-functions %t -- -- -U__STDC_LIB_EXT1__ -U__STDC_WANT_LIB_EXT1__
+// RUN: %check_clang_tidy -check-suffix=WITHOUT-ANNEX-K %s bugprone-unsafe-functions %t -- -- -D__STDC_LIB_EXT1__=1 -U__STDC_WANT_LIB_EXT1__
+// RUN: %check_clang_tidy -check-suffix=WITHOUT-ANNEX-K %s bugprone-unsafe-functions %t -- -- -U__STDC_LIB_EXT1__ -D__STDC_WANT_LIB_EXT1__=1
+// RUN: %check_clang_tidy -std=c11-or-later -check-suffix=WITH-ANNEX-K-CERT-ONLY %s bugprone-unsafe-functions %t -- \
// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.ReportMoreUnsafeFunctions: false}}" \
// RUN: -- -D__STDC_LIB_EXT1__=1 -D__STDC_WANT_LIB_EXT1__=1
-// RUN: %check_clang_tidy -check-suffix=WITH-NONE-ENABLED %s bugprone-unsafe-functions %t --\
+// RUN: %check_clang_tidy -check-suffix=WITH-NONE-ENABLED %s bugprone-unsafe-functions %t --\
// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.ReportDefaultFunctions: false}}" \
// RUN: -- -D__STDC_LIB_EXT1__=1 -D__STDC_WANT_LIB_EXT1__=1
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp
index 721c55b..5dd2387 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp
@@ -69,14 +69,14 @@ template<typename T>
T qux(T Generic) {
async::Future<Units> PendingA = acquireUnits();
auto PendingB = acquireUnits();
- // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'async::Future<Units>') [bugprone-unused-local-non-trivial-variable]
async::Future<Units> MustBeUsed;
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: unused local variable 'MustBeUsed' of type 'async::Future<Units>' [bugprone-unused-local-non-trivial-variable]
PendingA.get();
async::Future<T> TemplateType;
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable]
a::Future<T> AliasTemplateType;
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<T>') [bugprone-unused-local-non-trivial-variable]
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'async::Future<T>') [bugprone-unused-local-non-trivial-variable]
[[maybe_unused]] async::Future<Units> MaybeUnused;
return Generic;
}
@@ -86,7 +86,7 @@ async::Future<int> Global;
int bar(int Num) {
a::Future<Units> PendingA = acquireUnits();
a::Future<Units> PendingB = acquireUnits(); // not used at all, unused variable not fired because of destructor side effect
- // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'async::Future<Units>') [bugprone-unused-local-non-trivial-variable]
auto Num2 = PendingA.get();
auto Num3 = qux(Num);
async::Ptr<a::Future<Units>> Shared = async::Ptr<a::Future<Units>>(acquireUnits());
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cert/uppercase-literal-suffix-integer.cpp b/clang-tools-extra/test/clang-tidy/checkers/cert/uppercase-literal-suffix-integer.cpp
index 6fa700b..e7c0dd6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cert/uppercase-literal-suffix-integer.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cert/uppercase-literal-suffix-integer.cpp
@@ -1,14 +1,9 @@
// RUN: %check_clang_tidy %s cert-dcl16-c %t -- -- -I %clang_tidy_headers
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -checks='-*,cert-dcl16-c' -fix -- -I %clang_tidy_headers
-// RUN: clang-tidy %t.cpp -checks='-*,cert-dcl16-c' -warnings-as-errors='-*,cert-dcl16-c' -- -I %clang_tidy_headers
#include "integral_constant.h"
void integer_suffix() {
static constexpr auto v0 = __LINE__; // synthetic
- static_assert(v0 == 9 || v0 == 5, "");
-
static constexpr auto v1 = __cplusplus; // synthetic, long
static constexpr auto v2 = 1; // no literal
@@ -29,9 +24,6 @@ void integer_suffix() {
static constexpr auto v5 = 1l;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'l', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 1l;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}L{{$}}
// CHECK-FIXES: static constexpr auto v5 = 1L;
static_assert(is_same<decltype(v5), const long>::value, "");
static_assert(v5 == 1, "");
@@ -44,9 +36,6 @@ void integer_suffix() {
static constexpr auto v7 = 1ll;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'll', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1ll;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}LL{{$}}
// CHECK-FIXES: static constexpr auto v7 = 1LL;
static_assert(is_same<decltype(v7), const long long>::value, "");
static_assert(v7 == 1, "");
@@ -77,27 +66,18 @@ void integer_suffix() {
static constexpr auto v13 = 1lu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v13 = 1lu;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}LU{{$}}
// CHECK-FIXES: static constexpr auto v13 = 1LU;
static_assert(is_same<decltype(v13), const unsigned long>::value, "");
static_assert(v13 == 1, "");
static constexpr auto v14 = 1Lu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Lu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1Lu;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}LU{{$}}
// CHECK-FIXES: static constexpr auto v14 = 1LU;
static_assert(is_same<decltype(v14), const unsigned long>::value, "");
static_assert(v14 == 1, "");
static constexpr auto v15 = 1lU;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lU', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1lU;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}LU{{$}}
// CHECK-FIXES: static constexpr auto v15 = 1LU;
static_assert(is_same<decltype(v15), const unsigned long>::value, "");
static_assert(v15 == 1, "");
@@ -128,27 +108,18 @@ void integer_suffix() {
static constexpr auto v21 = 1llu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v21 = 1llu;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}LLU{{$}}
// CHECK-FIXES: static constexpr auto v21 = 1LLU;
static_assert(is_same<decltype(v21), const unsigned long long>::value, "");
static_assert(v21 == 1, "");
static constexpr auto v22 = 1LLu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'LLu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v22 = 1LLu;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}LLU{{$}}
// CHECK-FIXES: static constexpr auto v22 = 1LLU;
static_assert(is_same<decltype(v22), const unsigned long long>::value, "");
static_assert(v22 == 1, "");
static constexpr auto v23 = 1llU;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llU', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v23 = 1llU;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: {{^ *| *}}LLU{{$}}
// CHECK-FIXES: static constexpr auto v23 = 1LLU;
static_assert(is_same<decltype(v23), const unsigned long long>::value, "");
static_assert(v23 == 1, "");
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/prefer-member-initializer.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/prefer-member-initializer.cpp
index 7d61649..e8d7db1 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/prefer-member-initializer.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/prefer-member-initializer.cpp
@@ -650,3 +650,16 @@ struct InitFromBindingDecl {
}
};
} // namespace GH82970
+
+struct A {
+ int m;
+};
+
+struct B : A {
+ B() { m = 0; }
+};
+
+template <class T>
+struct C : A {
+ C() { m = 0; }
+};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.cpp
new file mode 100644
index 0000000..30d03bd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access.cpp
@@ -0,0 +1,341 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: split-file %s %t
+
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=DEFAULT %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- -- -I%t
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=AT %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: at}}' -- -I%t
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=FUNC %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: function, \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixFunction: "f"}}' -- -I%t
+
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=DEFAULT-NO-EXCL %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-no-excl.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.ExcludeClasses: ""}}' -- -I%t
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=AT-NO-EXCL %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-no-excl.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.ExcludeClasses: "", \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: at}}' -- -I%t
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=FUNC-NO-EXCL %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-no-excl.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.ExcludeClasses: "", \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: function, \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixFunction: "f"}}' -- -I%t
+
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=DEFAULT-EXCL %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-excl.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.ExcludeClasses: "ExcludedClass1;ExcludedClass2"}}' -- -I%t
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=AT-EXCL %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-excl.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.ExcludeClasses: "ExcludedClass1;ExcludedClass2", \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: at}}' -- -I%t
+
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 -check-suffix=FUNC-EXCL %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-excl.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.ExcludeClasses: "ExcludedClass1;ExcludedClass2", \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: function, \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixFunction: "f"}}' -- -I%t
+
+
+// RUN: %check_clang_tidy -std=c++23 -check-suffixes=DEFAULT-CXX-23 %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-cxx-23.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- -- -I%t -DCXX_23=1
+
+// RUN: %check_clang_tidy -std=c++23 -check-suffixes=AT-CXX-23 %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-cxx-23.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: at}}' -- -I%t -DCXX_23=1
+
+// RUN: %check_clang_tidy -std=c++23 -check-suffixes=FUNC-CXX-23 %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-cxx-23.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: function, \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixFunction: "f"}}' -- -I%t -DCXX_23=1
+
+// RUN: %check_clang_tidy -std=c++23 -check-suffixes=FUNC-EMPTY-ARGS-CXX-23 %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-cxx-23.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: function, \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixFunction: "f", cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixFunctionEmptyArgs: "g", }}' -- -I%t -DCXX_23=1
+
+// RUN: %check_clang_tidy -std=c++23 -check-suffix=FUNC-EMPTY-ARGS-EMPTY-CXX-23 %t/cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-cxx-23.cpp \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access %t -- \
+// RUN: -config='{CheckOptions: {cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixMode: function, \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.FixFunctionEmptyArgs: "", }}' -- -I%t -DCXX_23=1
+
+//--- cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.h
+
+namespace std {
+ template<typename T, unsigned size>
+ struct array {
+ T operator[](unsigned i) {
+ return T{1};
+ }
+ T at(unsigned i) {
+ return T{1};
+ }
+ T at() {
+ return T{1};
+ }
+ };
+
+ template<typename T, typename V>
+ struct map {
+ T operator[](unsigned i) {
+ return T{1};
+ }
+ T at(unsigned i) {
+ return T{1};
+ }
+ };
+
+ template<typename T>
+ struct unique_ptr {
+ T operator[](unsigned i) {
+ return T{1};
+ }
+ };
+
+ template<typename T>
+ struct span {
+ T operator[](unsigned i) {
+ return T{1};
+ }
+ };
+} // namespace std
+
+namespace json {
+ template<typename T>
+ struct node{
+ T operator[](unsigned i) {
+ return T{1};
+ }
+ };
+} // namespace json
+
+//--- cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.cpp
+
+#include "cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.h"
+
+struct SubClass : std::array<int, 3> {};
+
+template<class T> int f(T, unsigned){ return 0;}
+template<class T> int f(T){ return 0;}
+
+std::array<int, 3> a;
+
+auto b = a[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto b = a.at(0);
+// CHECK-FIXES-FUNC: auto b = f(a, 0);
+
+auto c = a[1+1];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto c = a.at(1+1);
+// CHECK-FIXES-FUNC: auto c = f(a, 1+1);
+
+constexpr int Index = 1;
+
+auto d = a[Index];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto d = a.at(Index);
+// CHECK-FIXES-FUNC: auto d = f(a, Index);
+
+int e(int Ind) {
+ return a[Ind];
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+ // CHECK-FIXES-AT: return a.at(Ind);
+ // CHECK-FIXES-FUNC: return f(a, Ind);
+}
+
+auto fa = (&a)->operator[](1);
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto fa = (&a)->at(1);
+// CHECK-FIXES-FUNC: auto fa = f(*(&a), 1);
+
+auto fd = a.operator[](1);
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto fd = a.at(1);
+// CHECK-FIXES-FUNC: auto fd = f(a, 1);
+
+
+
+auto g = a.at(0);
+
+std::unique_ptr<int> p;
+auto q = p[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto q = p[0];
+// CHECK-FIXES-FUNC: auto q = f(p, 0);
+
+std::span<int> s;
+auto t = s[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto t = s[0];
+// CHECK-FIXES-FUNC: auto t = f(s, 0);
+
+json::node<int> n;
+auto m = n[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto m = n[0];
+// CHECK-FIXES-FUNC: auto m = f(n, 0);
+
+SubClass Sub;
+auto r = Sub[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:13: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto r = Sub.at(0);
+// CHECK-FIXES-FUNC: auto r = f(Sub, 0);
+
+typedef std::array<int, 3> ar;
+ar BehindDef;
+auto u = BehindDef[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:19: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto u = BehindDef.at(0);
+// CHECK-FIXES-FUNC: auto u = f(BehindDef, 0);
+
+template<typename T> int TestTemplate(T t){
+ return t[0];
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:10: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+
+}
+
+
+auto v = TestTemplate<>(a);
+auto w = TestTemplate<>(p);
+
+#define SUBSCRIPT_BEHIND_MACRO(x) a[x]
+#define ARG_BEHIND_MACRO 0
+#define OBJECT_BEHIND_MACRO a
+
+auto m1 = SUBSCRIPT_BEHIND_MACRO(0);
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+
+auto m2 = a[ARG_BEHIND_MACRO];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:12: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto m2 = a.at(ARG_BEHIND_MACRO);
+// CHECK-FIXES-FUNC: auto m2 = f(a, ARG_BEHIND_MACRO);
+
+auto m3 = OBJECT_BEHIND_MACRO[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:30: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto m3 = OBJECT_BEHIND_MACRO.at(0);
+// CHECK-FIXES-FUNC: auto m3 = f(OBJECT_BEHIND_MACRO, 0);
+
+// Check that spacing does not invalidate the fixes
+std::array<int , 3> longname;
+
+auto z1 = longname [ 0 ] ;
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:22: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto z1 = longname .at( 0 ) ;
+// CHECK-FIXES-FUNC: auto z1 = f(longname , 0 ) ;
+auto z2 = longname . operator[] ( 0 );
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto z2 = longname . at ( 0 );
+// CHECK-FIXES-FUNC: auto z2 = f(longname , 0 );
+auto z3 = (&longname) -> operator[] ( 0 );
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT: auto z3 = (&longname) -> at ( 0 );
+// CHECK-FIXES-FUNC: auto z3 = f(*(&longname) , 0 );
+
+
+//--- cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-no-excl.cpp
+
+#include "cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.h"
+
+class ExcludedClass1 {
+ public:
+ int operator[](unsigned i) {
+ return 1;
+ }
+ int at(unsigned i) {
+ return 1;
+ }
+};
+
+class ExcludedClass2 {
+ public:
+ int operator[](unsigned i) {
+ return 1;
+ }
+ int at(unsigned i) {
+ return 1;
+ }
+};
+
+ExcludedClass1 E1;
+auto x1 = E1[0];
+// CHECK-MESSAGES-DEFAULT-NO-EXCL: :[[@LINE-1]]:13: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT-NO-EXCL: auto x1 = E1.at(0);
+// CHECK-FIXES-FUNC-NO-EXCL: auto x1 = f(E1, 0);
+
+ExcludedClass2 E2;
+auto x2 = E2[0];
+// CHECK-MESSAGES-DEFAULT-NO-EXCL: :[[@LINE-1]]:13: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT-NO-EXCL: auto x2 = E2.at(0);
+// CHECK-FIXES-FUNC-NO-EXCL: auto x2 = f(E2, 0);
+
+std::map<int,int> TestMapNoExcl;
+auto y = TestMapNoExcl[0];
+// CHECK-MESSAGES-DEFAULT-NO-EXCL: :[[@LINE-1]]:23: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT-NO-EXCL: auto y = TestMapNoExcl.at(0);
+// CHECK-FIXES-FUNC-NO-EXCL: auto y = f(TestMapNoExcl, 0);
+
+
+//--- cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-excl.cpp
+
+#include "cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.h"
+
+std::map<int,int> TestMapExcl;
+auto y = TestMapExcl[0];
+// CHECK-MESSAGES-DEFAULT-EXCL: :[[@LINE-1]]:21: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT-EXCL: auto y = TestMapExcl.at(0);
+// CHECK-FIXES-FUNC-EXCL: auto y = f(TestMapExcl, 0);
+
+
+//--- cppcoreguidelines-pro-bounds-avoid-unchecked-container-access-cxx-23.cpp
+#ifdef CXX_23
+#include "cppcoreguidelines-pro-bounds-avoid-unchecked-container-access.h"
+
+namespace std {
+ template<typename T, unsigned size>
+ struct array_cxx_23 {
+ T operator[]() {
+ return T{1};
+ }
+ T at() {
+ return T{1};
+ }
+ };
+};
+
+std::array_cxx_23<int, 3> a;
+
+auto b23 = a[];
+// CHECK-MESSAGES-DEFAULT-CXX-23: :[[@LINE-1]]:13: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT-CXX-23: auto b23 = a.at();
+// CHECK-FIXES-FUNC-CXX-23: auto b23 = f(a);
+// CHECK-FIXES-FUNC-EMPTY-ARGS-CXX-23: auto b23 = g(a);
+// CHECK-MESSAGES-FUNC-EMPTY-ARGS-EMPTY-CXX-23: :[[@LINE-5]]:13: warning: possibly unsafe 'operator[]' [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-MESSAGES-FUNC-EMPTY-ARGS-EMPTY-CXX-23-NOT: :[[@LINE-6]]:{{.*}}: note: FIX-IT applied suggested code changes
+
+auto fa23 = (&a)->operator[]();
+// CHECK-MESSAGES-DEFAULT-CXX-23: :[[@LINE-1]]:13: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT-CXX-23: auto fa23 = (&a)->at();
+// CHECK-FIXES-FUNC-CXX-23: auto fa23 = f(*(&a));
+// CHECK-FIXES-FUNC-EMPTY-ARGS-CXX-23: auto fa23 = g(*(&a));
+// CHECK-MESSAGES-FUNC-EMPTY-ARGS-EMPTY-CXX-23: :[[@LINE-5]]:13: warning: possibly unsafe 'operator[]' [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-MESSAGES-FUNC-EMPTY-ARGS-EMPTY-CXX-23-NOT: :[[@LINE-6]]:{{.*}}: note: FIX-IT applied suggested code changes
+
+auto fd23 = a.operator[]();
+// CHECK-MESSAGES-DEFAULT-CXX-23: :[[@LINE-1]]:13: warning: possibly unsafe 'operator[]', consider bounds-safe alternatives [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-FIXES-AT-CXX-23: auto fd23 = a.at();
+// CHECK-FIXES-FUNC-CXX-23: auto fd23 = f(a);
+// CHECK-FIXES-FUNC-EMPTY-ARGS-CXX-23: auto fd23 = g(a);
+// CHECK-MESSAGES-FUNC-EMPTY-ARGS-EMPTY-CXX-23: :[[@LINE-5]]:13: warning: possibly unsafe 'operator[]' [cppcoreguidelines-pro-bounds-avoid-unchecked-container-access]
+// CHECK-MESSAGES-FUNC-EMPTY-ARGS-EMPTY-CXX-23-NOT: :[[@LINE-6]]:{{.*}}: note: FIX-IT applied suggested code changes
+#endif
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-pointer-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-pointer-arithmetic.cpp
index aed6080..fa81c13 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-pointer-arithmetic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-pointer-arithmetic.cpp
@@ -1,4 +1,6 @@
-// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-pointer-arithmetic %t
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-pointer-arithmetic -check-suffixes=,DEFAULT %t
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-pointer-arithmetic %t -- \
+// RUN: -config="{CheckOptions: {cppcoreguidelines-pro-bounds-pointer-arithmetic.AllowIncrementDecrementOperators: true}}" --
enum E {
ENUM_LITERAL = 1
@@ -42,14 +44,14 @@ void fail() {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
p++;
- // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
++p;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
p--;
- // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
--p;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
i = p[1];
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use pointer arithmetic
@@ -57,7 +59,7 @@ void fail() {
p = ip + 1;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: do not use pointer arithmetic
ip++;
- // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
i = ip[1];
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use pointer arithmetic
}
@@ -72,7 +74,7 @@ void template_fail() {
q = p - 1;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
p++;
- // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
+ // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
i = p[1];
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use pointer arithmetic
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/google/objc-function-naming.m b/clang-tools-extra/test/clang-tidy/checkers/google/objc-function-naming.m
index 4c204c7..13d00a8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/google/objc-function-naming.m
+++ b/clang-tools-extra/test/clang-tidy/checkers/google/objc-function-naming.m
@@ -8,7 +8,7 @@ static void TestImplicitFunctionDeclaration(int a) {
printf("%d", a);
}
-typedef _Bool bool;
+#define bool _Bool
static bool ispositive(int a) { return a > 0; }
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: static function named 'ispositive'
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-different-visibility/test-system-header.h b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-different-visibility/test-system-header.h
new file mode 100644
index 0000000..e64e192
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-different-visibility/test-system-header.h
@@ -0,0 +1,14 @@
+#pragma clang system_header
+
+namespace sys {
+
+struct Base {
+ virtual void publicF();
+};
+
+struct Derived: public Base {
+private:
+ void publicF() override;
+};
+
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-ignore.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-ignore.cpp
new file mode 100644
index 0000000..934cfb7
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-ignore.cpp
@@ -0,0 +1,60 @@
+// RUN: %check_clang_tidy %s misc-override-with-different-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.IgnoredFunctions: 'IgnoreAlways::.*;::a::IgnoreSelected::.*;IgnoreFunctions::f1;ignored_f'}}"
+
+class IgnoreAlways {
+ virtual void f();
+};
+
+class IgnoreSelected {
+ virtual void f();
+};
+
+namespace a {
+class IgnoreAlways {
+ virtual void f();
+};
+class IgnoreSelected {
+ virtual void f();
+};
+}
+
+namespace ignore_always {
+class Test1: public IgnoreAlways {
+public:
+ void f();
+ void ignored_f(int);
+};
+class Test2: public a::IgnoreAlways {
+public:
+ void f();
+};
+}
+
+namespace ignore_selected {
+class Test1: public IgnoreSelected {
+public:
+ void f();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'f'
+ // CHECK-MESSAGES: :9:16: note: function declared here
+ void ignored_f(int);
+};
+class Test2: public a::IgnoreSelected {
+public:
+ void f();
+};
+}
+
+class IgnoreFunctions {
+ virtual void f1();
+ virtual void f2();
+ virtual void ignored_f();
+};
+
+class IgnoreFunctionsTest: public IgnoreFunctions {
+public:
+ void f1();
+ void f2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'f2'
+ // CHECK-MESSAGES: :[[@LINE-9]]:16: note: function declared here
+ void ignored_f();
+};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-options.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-options.cpp
new file mode 100644
index 0000000..0a363dd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-options.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy -check-suffixes=DTORS,WIDENING,NARROWING %s misc-override-with-different-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.CheckDestructors: true}}"
+
+// RUN: %check_clang_tidy -check-suffixes=OPS,WIDENING,NARROWING %s misc-override-with-different-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.CheckOperators: true}}"
+
+// RUN: %check_clang_tidy -check-suffixes=WIDENING %s misc-override-with-different-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.DisallowedVisibilityChange: 'widening'}}"
+
+// RUN: %check_clang_tidy -check-suffixes=NARROWING %s misc-override-with-different-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.DisallowedVisibilityChange: 'narrowing'}}"
+
+namespace test_change {
+
+class A {
+protected:
+ virtual void f1();
+ virtual void f2();
+};
+
+class B: public A {
+public:
+ void f1();
+ // CHECK-MESSAGES-WIDENING: :[[@LINE-1]]:8: warning: visibility of function 'f1'
+ // CHECK-MESSAGES-WIDENING: :[[@LINE-8]]:16: note: function declared here
+private:
+ void f2();
+ // CHECK-MESSAGES-NARROWING: :[[@LINE-1]]:8: warning: visibility of function 'f2'
+ // CHECK-MESSAGES-NARROWING: :[[@LINE-11]]:16: note: function declared here
+};
+
+}
+
+namespace test_destructor {
+
+class A {
+public:
+ virtual ~A();
+};
+
+class B: public A {
+protected:
+ ~B();
+ // CHECK-MESSAGES-DTORS: :[[@LINE-1]]:3: warning: visibility of function '~B'
+ // CHECK-MESSAGES-DTORS: :[[@LINE-7]]:11: note: function declared here
+};
+
+}
+
+namespace test_operator {
+
+class A {
+ virtual A& operator=(const A&);
+ virtual A& operator++();
+ virtual int operator()(int);
+ virtual operator double() const;
+};
+
+class B: public A {
+protected:
+ A& operator=(const A&);
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:6: warning: visibility of function 'operator='
+ // CHECK-MESSAGES-OPS: :[[@LINE-10]]:14: note: function declared here
+ A& operator++();
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:6: warning: visibility of function 'operator++'
+ // CHECK-MESSAGES-OPS: :[[@LINE-12]]:14: note: function declared here
+ int operator()(int);
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:7: warning: visibility of function 'operator()'
+ // CHECK-MESSAGES-OPS: :[[@LINE-14]]:15: note: function declared here
+ operator double() const;
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:3: warning: visibility of function 'operator double'
+ // CHECK-MESSAGES-OPS: :[[@LINE-16]]:11: note: function declared here
+};
+
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility.cpp
new file mode 100644
index 0000000..fd541a4
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility.cpp
@@ -0,0 +1,289 @@
+// RUN: %check_clang_tidy %s misc-override-with-different-visibility %t -- -config="{CheckOptions: {misc-override-with-different-visibility.CheckDestructors: true,misc-override-with-different-visibility.CheckOperators: true}}" -- -I %S/Inputs/override-with-different-visibility
+#include <test-system-header.h>
+class A {
+public:
+ virtual void pub_foo1() {}
+ virtual void pub_foo2() {}
+ virtual void pub_foo3() {}
+protected:
+ virtual void prot_foo1();
+ virtual void prot_foo2();
+ virtual void prot_foo3();
+private:
+ virtual void priv_foo1() {}
+ virtual void priv_foo2() {}
+ virtual void priv_foo3() {}
+};
+
+void A::prot_foo1() {}
+void A::prot_foo2() {}
+void A::prot_foo3() {}
+
+namespace test1 {
+
+class B: public A {
+public:
+ void pub_foo1() override {}
+ void prot_foo1() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from protected in class 'A' to public [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :9:16: note: function declared here as protected
+ void priv_foo1() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo1' is changed from private in class 'A' to public [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :13:16: note: function declared here as private
+protected:
+ void pub_foo2() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo2' is changed from public in class 'A' to protected [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :6:16: note: function declared here as public
+ void prot_foo2() override {}
+ void priv_foo2() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo2' is changed from private in class 'A' to protected [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :14:16: note: function declared here as private
+private:
+ void pub_foo3() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo3' is changed from public in class 'A' to private [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :7:16: note: function declared here as public
+ void prot_foo3() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo3' is changed from protected in class 'A' to private [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :11:16: note: function declared here as protected
+ void priv_foo3() override {}
+};
+
+class C: public B {
+public:
+ void pub_foo1() override;
+protected:
+ void prot_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from public in class 'B' to protected [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :27:8: note: function declared here as public
+private:
+ void priv_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo1' is changed from public in class 'B' to private [misc-override-with-different-visibility]
+ // CHECK-MESSAGES: :30:8: note: function declared here as public
+};
+
+void C::prot_foo1() {}
+void C::priv_foo1() {}
+
+}
+
+namespace test2 {
+
+class B: public A {
+public:
+ void pub_foo1() override;
+protected:
+ void prot_foo1() override;
+private:
+ void priv_foo1() override;
+};
+
+class C: public B {
+public:
+ void pub_foo1() override;
+ void prot_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from protected in class 'B' to public
+ // CHECK-MESSAGES: :75:8: note: function declared here as protected
+ void priv_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo1' is changed from private in class 'B' to public
+ // CHECK-MESSAGES: :77:8: note: function declared here as private
+
+ void pub_foo2() override;
+ void prot_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo2' is changed from protected in class 'A' to public
+ // CHECK-MESSAGES: :10:16: note: function declared here as protected
+ void priv_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo2' is changed from private in class 'A' to public
+ // CHECK-MESSAGES: :14:16: note: function declared here as private
+};
+
+}
+
+namespace test3 {
+
+class B: private A {
+public:
+ void pub_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo1' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :103:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :5:16: note: function declared here as public
+protected:
+ void prot_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from private (through private inheritance of class 'A') to protected
+ // CHECK-MESSAGES: :103:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :9:16: note: function declared here as protected
+private:
+ void priv_foo1() override;
+
+public:
+ void prot_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo2' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :103:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :10:16: note: function declared here as protected
+ void priv_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo2' is changed from private in class 'A' to public
+ // CHECK-MESSAGES: :14:16: note: function declared here as private
+
+private:
+ void pub_foo3() override;
+ void prot_foo3() override;
+};
+
+class C: private A {
+};
+
+class D: public C {
+public:
+ void pub_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo1' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :131:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :5:16: note: function declared here as public
+};
+
+
+}
+
+namespace test4 {
+
+struct Base1 {
+public:
+ virtual void foo1();
+private:
+ virtual void foo2();
+};
+
+struct Base2 {
+public:
+ virtual void foo2();
+private:
+ virtual void foo1();
+};
+
+struct A : public Base1, public Base2 {
+protected:
+ void foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'foo1' is changed from private in class 'Base2' to protected
+ // CHECK-MESSAGES: :158:16: note: function declared here as private
+ // CHECK-MESSAGES: :[[@LINE-3]]:8: warning: visibility of function 'foo1' is changed from public in class 'Base1' to protected
+ // CHECK-MESSAGES: :149:16: note: function declared here as public
+private:
+ void foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'foo2' is changed from public in class 'Base2' to private
+ // CHECK-MESSAGES: :156:16: note: function declared here as public
+};
+
+}
+
+namespace test5 {
+
+struct B1: virtual public A {};
+struct B2: virtual private A {};
+struct B: public B1, public B2 {
+public:
+ void pub_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo1' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :179:12: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :5:16: note: function declared here as public
+};
+
+}
+
+namespace test_using {
+
+class A {
+private:
+ A(int);
+protected:
+ virtual void f();
+};
+
+class B: public A {
+public:
+ using A::A;
+ using A::f;
+};
+
+}
+
+namespace test_template {
+
+template <typename T>
+class A {
+protected:
+ virtual T foo();
+};
+
+template <typename T>
+class B: public A<T> {
+private:
+ T foo() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: visibility of function 'foo' is changed from protected in class 'A<int>' to private
+ // CHECK-MESSAGES: :[[@LINE-8]]:13: note: function declared here as protected
+};
+
+template <typename T>
+class C: private A<T> {
+public:
+ T foo() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: visibility of function 'foo' is changed from private (through private inheritance of class 'A<int>') to public
+ // CHECK-MESSAGES: :[[@LINE-4]]:10: note: 'A<int>' is inherited as private here
+ // CHECK-MESSAGES: :[[@LINE-17]]:13: note: function declared here as protected
+};
+
+B<int> fB() {
+ return B<int>{};
+}
+
+C<int> fC() {
+ return C<int>{};
+}
+
+}
+
+namespace test_system_header {
+
+struct SysDerived: public sys::Base {
+private:
+ void publicF();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'publicF' is changed from public in class 'Base' to private
+};
+
+}
+
+namespace test_destructor {
+
+class A {
+public:
+ virtual ~A();
+};
+
+class B: public A {
+protected:
+ ~B();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: visibility of function '~B'
+ // CHECK-MESSAGES: :[[@LINE-7]]:11: note: function declared here
+};
+
+}
+
+namespace test_operator {
+
+class A {
+ virtual int operator()(int);
+ virtual A& operator++();
+ virtual operator double() const;
+};
+
+class B: public A {
+protected:
+ int operator()(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: visibility of function 'operator()'
+ // CHECK-MESSAGES: :[[@LINE-9]]:15: note: function declared here
+ A& operator++();
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: visibility of function 'operator++'
+ // CHECK-MESSAGES: :[[@LINE-11]]:14: note: function declared here
+ operator double() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: visibility of function 'operator double'
+ // CHECK-MESSAGES: :[[@LINE-13]]:11: note: function declared here
+};
+
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.c b/clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.c
index 77262c2..b83a093 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.c
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-static-assert %t -- -- -std=c11
+// RUN: %check_clang_tidy -std=c11-or-later %s misc-static-assert %t
// RUN: clang-tidy %s -checks=-*,misc-static-assert -- -std=c99 | count 0
void abort(void) {}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/unconventional-assign-operator.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/unconventional-assign-operator.cpp
index 28b53ae..d7a5797 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/unconventional-assign-operator.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/unconventional-assign-operator.cpp
@@ -176,3 +176,11 @@ struct TemplateAssignment {
}
};
}
+
+namespace GH153770 {
+ struct A;
+ struct A {
+ A() = default;
+ A& operator=(const A&) = default;
+ };
+} // namespace GH153770
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.c b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.c
index bde93ea..e2f501c7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.c
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-unused-parameters %t -- -- -Wno-strict-prototypes -xc
+// RUN: %check_clang_tidy %s misc-unused-parameters %t -- -- -Wno-strict-prototypes
// Basic removal
// =============
@@ -6,14 +6,18 @@ void a(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
-static void b(); // In C, forward declarations can leave out parameters.
+#if __STDC_VERSION__ < 202311L
+static void b(); // In C before C23, forward declarations can leave out parameters.
+#endif
static void b(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: {{^}}static void b() {;}{{$}}
// Unchanged cases
// ===============
+#if __STDC_VERSION__ < 202311L
void h(i, c, d) int i; char *c, *d; {} // Don't mess with K&R style
+#endif
// Do not warn on naked functions.
__attribute__((naked)) void nakedFunction(int a, int b) { ; }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/make-shared.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-shared.cpp
index e57f45c..65ece77 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/make-shared.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-shared.cpp
@@ -109,6 +109,8 @@ void basic() {
}
std::shared_ptr<int> R(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<int> R = std::make_shared<int>();
std::shared_ptr<int> S(new int);
// Create the shared_ptr as a parameter to a function.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp
index e665ca0..13103c7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp
@@ -154,6 +154,8 @@ void basic() {
}
std::unique_ptr<int> R(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<int> R = std::make_unique<int>();
std::unique_ptr<int> S(new int);
// Create the unique_ptr as a parameter to a function.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-GH153649.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-GH153649.cpp
new file mode 100644
index 0000000..142eb58
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-GH153649.cpp
@@ -0,0 +1,15 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-type-traits %t
+
+namespace std {
+template <class> struct tuple_size {
+ static const int value = 1;
+};
+template <int, class> struct tuple_element {
+ using type = int;
+};
+}
+
+struct A {};
+template <int> int get(const A&);
+
+auto [a] = A();
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp
index 3bcd5cd..90131c3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++20 %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing
// NOLINTBEGIN
namespace std {
@@ -756,3 +756,69 @@ abs(const number<T, ExpressionTemplates> &v) {
}
}
+
+template <typename T>
+struct some_type_trait {
+ static constexpr bool value = true;
+};
+
+// Fix-its are offered even for a non-standard enable_if.
+namespace nonstd {
+
+template <bool Condition, typename T = void>
+struct enable_if : std::enable_if<Condition, T> {};
+
+template <bool Condition, typename T = void>
+using enable_if_t = typename enable_if<Condition, T>::type;
+
+}
+
+template <typename T>
+typename nonstd::enable_if<some_type_trait<T>::value, void>::type nonstd_enable_if() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
+// CHECK-FIXES: {{^}}void nonstd_enable_if() requires some_type_trait<T>::value {}{{$}}
+
+template <typename T>
+nonstd::enable_if_t<some_type_trait<T>::value, void> nonstd_enable_if_t() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
+// CHECK-FIXES: {{^}}void nonstd_enable_if_t() requires some_type_trait<T>::value {}{{$}}
+
+template <>
+nonstd::enable_if_t<some_type_trait<int>::value, void> nonstd_enable_if_t<int>() {}
+// FIXME - Support non-dependent enable_ifs.
+
+template <typename T>
+typename nonstd::enable_if<some_type_trait<T>::value>::type nonstd_enable_if_one_param() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
+// CHECK-FIXES: {{^}}void nonstd_enable_if_one_param() requires some_type_trait<T>::value {}{{$}}
+
+template <typename T>
+nonstd::enable_if_t<some_type_trait<T>::value> nonstd_enable_if_t_one_param() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
+// CHECK-FIXES: {{^}}void nonstd_enable_if_t_one_param() requires some_type_trait<T>::value {}{{$}}
+
+// No fix-its are offered for an enable_if with a different signature from the standard one.
+namespace boost {
+
+template <typename Condition, typename T = void>
+struct enable_if : std::enable_if<Condition::value, T> {};
+
+template <typename Condition, typename T = void>
+using enable_if_t = typename enable_if<Condition, T>::type;
+
+}
+
+template <typename T>
+typename boost::enable_if<some_type_trait<T>, void>::type boost_enable_if() {}
+
+template <typename T>
+boost::enable_if_t<some_type_trait<T>, void> boost_enable_if_t() {}
+
+template <>
+boost::enable_if_t<some_type_trait<int>, void> boost_enable_if_t<int>() {}
+
+template <typename T>
+typename boost::enable_if<some_type_trait<T>>::type boost_enable_if_one_param() {}
+
+template <typename T>
+boost::enable_if_t<some_type_trait<T>> boost_enable_if_t_one_param() {}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c
index 6fb879b..d9b7ec2 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- -- -std=c23
+// RUN: %check_clang_tidy -std=c23-or-later %s modernize-use-nullptr %t
#define NULL 0
diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp
index 732cf5d..a38594a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp
@@ -43,25 +43,25 @@ template <class T>
class allocator {};
void simple(const std::vector<const char> &v, std::deque<const short> *d) {
- // CHECK-MESSAGES: [[#@LINE-1]]:24: warning: container using std::allocator<const T> is a deprecated libc++ extension; remove const for compatibility with other standard libraries
- // CHECK-MESSAGES: [[#@LINE-2]]:52: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:19: warning: container using std::allocator<const T> is a deprecated libc++ extension; remove const for compatibility with other standard libraries
+ // CHECK-MESSAGES: [[#@LINE-2]]:47: warning: container
std::list<const long> l;
- // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
std::multiset<int *const> ms;
- // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
std::set<const std::hash<int>> s;
- // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
std::unordered_multiset<int *const> ums;
- // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
std::unordered_set<const int> us;
- // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
absl::flat_hash_set<const int> fhs;
- // CHECK-MESSAGES: [[#@LINE-1]]:9: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
using my_vector = std::vector<const int>;
- // CHECK-MESSAGES: [[#@LINE-1]]:26: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:21: warning: container
my_vector v1;
using my_vector2 = my_vector;
@@ -76,7 +76,7 @@ void simple(const std::vector<const char> &v, std::deque<const short> *d) {
template <class T>
void temp1() {
std::vector<const T> v;
- // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
std::vector<T> neg1;
std::forward_list<const T> neg2;
@@ -87,7 +87,7 @@ template <class T>
void temp2() {
// Match std::vector<const dependent> for the uninstantiated temp2.
std::vector<const T> v;
- // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
+ // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
std::vector<T> neg1;
std::forward_list<const T> neg2;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/bitint-no-crash.c b/clang-tools-extra/test/clang-tidy/checkers/readability/bitint-no-crash.c
index f866092..01e458e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/bitint-no-crash.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/bitint-no-crash.c
@@ -1,6 +1,5 @@
-// RUN: %check_clang_tidy %s readability-magic-numbers %t --
+// RUN: %check_clang_tidy -std=c23-or-later %s readability-magic-numbers %t
// Don't crash
_BitInt(128) A = 4533629751480627964421wb;
-// CHECK-MESSAGES: warning
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
index 2fd0b222..6a67310 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
@@ -895,3 +895,93 @@ namespace PR94454 {
int operator""_ci() { return 0; }
auto eq = 0_ci == 0;
}
+
+namespace GH152387 {
+
+class foo : public std::string{
+ void doit() {
+ if (!size()) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used to check for emptiness instead of 'size'
+ // CHECK-FIXES: if (empty()) {
+ }
+ }
+};
+
+}
+
+namespace GH154762 {
+class TypeRange {
+ std::vector<int> b;
+
+public:
+ TypeRange(std::vector<int> b = {});
+ TypeRange(int);
+ bool operator==(const TypeRange& other) const;
+
+ size_t size() const {
+ return b.size();
+ }
+
+ bool empty() const {
+ return size() == 0;
+ }
+};
+
+void foo(std::vector<int> v) {
+ if (TypeRange(1) == TypeRange(v)) { // no warning
+ }
+
+ if (TypeRange(1) == TypeRange()) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the 'empty' method should be used to check for emptiness instead of comparing to an empty object
+ // CHECK-FIXES: if (TypeRange(1).empty()) {
+ }
+
+ if (TypeRange(v) == TypeRange()) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the 'empty' method should be used to check for emptiness instead of comparing to an empty object
+ // CHECK-FIXES: if (TypeRange(v).empty()) {
+ }
+}
+}
+
+class ReportInContainerNonEmptyMethod {
+public:
+ int size() const;
+ bool empty() const;
+
+ void doit() {
+ if (!size()) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used to check for emptiness instead of 'size'
+ // CHECK-FIXES: if (empty())
+ }
+ }
+};
+
+template <typename T>
+class ReportInTemplateContainerNonEmptyMethod {
+public:
+ int size() const;
+ bool empty() const;
+
+ void doit() {
+ if (!size()) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used to check for emptiness instead of 'size'
+ // CHECK-FIXES: if (empty()) {
+ }
+ }
+};
+
+
+
+class ReportInContainerNonEmptyMethodCompare {
+public:
+ bool operator==(const ReportInContainerNonEmptyMethodCompare& other) const;
+ int size() const;
+ bool empty() const;
+
+ void doit() {
+ if (*this == ReportInContainerNonEmptyMethodCompare()) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: the 'empty' method should be used to check for emptiness instead of comparing to an empty object
+ // CHECK-FIXES: if (this->empty()) {
+ }
+ }
+};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h
index e1036483..51fa9c3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h
@@ -50,8 +50,8 @@ typedef void* FILE; // NOLINT
#define NULL (0) // NOLINT
#ifndef __cplusplus
-typedef _Bool bool; // NOLINT
typedef __WCHAR_TYPE__ wchar_t; // NOLINT
+#define bool _Bool // NOLINT
#define true 1 // NOLINT
#define false 0 // NOLINT
#endif
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c
index 11ff7dd..5a4627a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c
@@ -1,8 +1,8 @@
-// RUN: %check_clang_tidy --match-partial-fixes %s readability-implicit-bool-conversion %t -- -- -std=c23
-// RUN: %check_clang_tidy -check-suffix=UPPER-CASE %s readability-implicit-bool-conversion %t -- \
+// RUN: %check_clang_tidy -std=c23-or-later --match-partial-fixes %s readability-implicit-bool-conversion %t
+// RUN: %check_clang_tidy -std=c23-or-later -check-suffix=UPPER-CASE %s readability-implicit-bool-conversion %t -- \
// RUN: -config='{CheckOptions: { \
// RUN: readability-implicit-bool-conversion.UseUpperCaseLiteralSuffix: true \
-// RUN: }}' -- -std=c23
+// RUN: }}'
#undef NULL
#define NULL 0L
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c
index db50467..e254215 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-non-const-parameter %t
+// RUN: %check_clang_tidy -std=c99,c11,c17 %s readability-non-const-parameter %t
static int f();
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-c23.c b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-c23.c
new file mode 100644
index 0000000..d8b104f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-c23.c
@@ -0,0 +1,120 @@
+// TODO: When Clang adds support for decimal floating point types, enable these tests by:
+// 1. Removing all the #if 0 + #endif guards.
+// 2. Removing all occurrences of the string "DISABLED-" in this file.
+// 3. Deleting this message.
+
+// RUN: %check_clang_tidy -std=c23-or-later %s readability-uppercase-literal-suffix %t
+
+void bit_precise_literal_suffix() {
+ // _BitInt()
+
+ static constexpr auto v1 = 1wb;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'wb', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v1 = 1WB;
+ static_assert(v1 == 1WB);
+
+ static constexpr auto v2 = 1WB; // OK.
+ static_assert(v2 == 1WB);
+
+ // _BitInt() Unsigned
+
+ static constexpr auto v3 = 1wbu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'wbu', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v3 = 1WBU;
+ static_assert(v3 == 1WBU);
+
+ static constexpr auto v4 = 1WBu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'WBu', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v4 = 1WBU;
+ static_assert(v4 == 1WBU);
+
+ static constexpr auto v5 = 1wbU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'wbU', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v5 = 1WBU;
+ static_assert(v5 == 1WBU);
+
+ static constexpr auto v6 = 1WBU; // OK.
+ static_assert(v6 == 1WBU);
+
+ // Unsigned _BitInt()
+
+ static constexpr auto v7 = 1uwb;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'uwb', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v7 = 1UWB;
+ static_assert(v7 == 1UWB);
+
+ static constexpr auto v8 = 1uWB;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'uWB', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v8 = 1UWB;
+ static_assert(v8 == 1UWB);
+
+ static constexpr auto v9 = 1Uwb;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'Uwb', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v9 = 1UWB;
+ static_assert(v9 == 1UWB);
+
+ static constexpr auto v10 = 1UWB; // OK.
+ static_assert(v10 == 1UWB);
+}
+
+void decimal_floating_point_suffix() {
+ // _Decimal32
+
+#if 0
+ static constexpr auto v1 = 1.df;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'df', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v1 = 1.DF;
+ static_assert(v1 == 1.DF);
+
+ static constexpr auto v2 = 1.e0df;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'df', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v2 = 1.e0DF;
+ static_assert(v2 == 1.DF);
+
+ static constexpr auto v3 = 1.DF; // OK.
+ static_assert(v3 == 1.DF);
+
+ static constexpr auto v4 = 1.e0DF; // OK.
+ static_assert(v4 == 1.DF);
+#endif
+
+ // _Decimal64
+
+#if 0
+ static constexpr auto v5 = 1.dd;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'dd', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v5 = 1.DD;
+ static_assert(v5 == 1.DD);
+
+ static constexpr auto v6 = 1.e0dd;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'dd', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v6 = 1.e0DD;
+ static_assert(v6 == 1.DD);
+
+ static constexpr auto v7 = 1.DD; // OK.
+ static_assert(v7 == 1.DD);
+
+ static constexpr auto v8 = 1.e0DD; // OK.
+ static_assert(v8 == 1.DD);
+#endif
+
+ // _Decimal128
+
+#if 0
+ static constexpr auto v9 = 1.dl;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'dl', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v9 = 1.DL;
+ static_assert(v9 == 1.DL);
+
+ static constexpr auto v10 = 1.e0dl;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'dl', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v10 = 1.e0DL;
+ static_assert(v10 == 1.DL);
+
+ static constexpr auto v11 = 1.DL; // OK.
+ static_assert(v11 == 1.DL);
+
+ static constexpr auto v12 = 1.e0DL; // OK.
+ static_assert(v12 == 1.DL);
+#endif
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-cxx23.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-cxx23.cpp
new file mode 100644
index 0000000..6602fd9
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-cxx23.cpp
@@ -0,0 +1,264 @@
+// TODO: When Clang adds support for C++23 floating-point types, enable these tests by:
+// 1. Removing all the #if 0 + #endif guards.
+// 2. Removing all occurrences of the string "DISABLED-" in this file.
+// 3. Deleting this message.
+// These suffixes may be relevant to C too: https://github.com/llvm/llvm-project/issues/97335
+
+// RUN: %check_clang_tidy -std=c++23-or-later %s readability-uppercase-literal-suffix %t -- -- -target aarch64-linux-gnu -I %clang_tidy_headers
+
+#include "integral_constant.h"
+#include <cstddef>
+#if 0
+#include <stdfloat>
+#endif
+
+void normal_literals() {
+ // std::bfloat16_t
+
+#if 0
+ static constexpr auto v1 = 1.bf16;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'bf16', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v1 = 1.BF16;
+ static_assert(is_same<decltype(v1), const std::bfloat16_t>::value, "");
+ static_assert(v1 == 1.BF16, "");
+
+ static constexpr auto v2 = 1.e0bf16;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'bf16', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v2 = 1.e0BF16;
+ static_assert(is_same<decltype(v2), const std::bfloat16_t>::value, "");
+ static_assert(v2 == 1.BF16, "");
+
+ static constexpr auto v3 = 1.BF16; // OK.
+ static_assert(is_same<decltype(v3), const std::bfloat16_t>::value, "");
+ static_assert(v3 == 1.BF16, "");
+
+ static constexpr auto v4 = 1.e0BF16; // OK.
+ static_assert(is_same<decltype(v4), const std::bfloat16_t>::value, "");
+ static_assert(v4 == 1.BF16, "");
+#endif
+
+ // _Float16/std::float16_t
+
+ static constexpr auto v5 = 1.f16;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f16', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v5 = 1.F16;
+ static_assert(is_same<decltype(v5), const _Float16>::value, "");
+ static_assert(v5 == 1.F16, "");
+
+ static constexpr auto v6 = 1.e0f16;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f16', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v6 = 1.e0F16;
+ static_assert(is_same<decltype(v6), const _Float16>::value, "");
+ static_assert(v6 == 1.F16, "");
+
+ static constexpr auto v7 = 1.F16; // OK.
+ static_assert(is_same<decltype(v7), const _Float16>::value, "");
+ static_assert(v7 == 1.F16, "");
+
+ static constexpr auto v8 = 1.e0F16; // OK.
+ static_assert(is_same<decltype(v8), const _Float16>::value, "");
+ static_assert(v8 == 1.F16, "");
+
+ // std::float32_t
+
+#if 0
+ static constexpr auto v9 = 1.f32;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f32', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v9 = 1.F32;
+ static_assert(is_same<decltype(v9), const std::float32_t>::value, "");
+ static_assert(v9 == 1.F32, "");
+
+ static constexpr auto v10 = 1.e0f32;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f32', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v10 = 1.e0F32;
+ static_assert(is_same<decltype(v10), const std::float32_t>::value, "");
+ static_assert(v10 == 1.F32, "");
+
+ static constexpr auto v11 = 1.F32; // OK.
+ static_assert(is_same<decltype(v11), const std::float32_t>::value, "");
+ static_assert(v11 == 1.F32, "");
+
+ static constexpr auto v12 = 1.e0F32; // OK.
+ static_assert(is_same<decltype(v12), const std::float32_t>::value, "");
+ static_assert(v12 == 1.F32, "");
+#endif
+
+ // std::float64_t
+
+#if 0
+ static constexpr auto v13 = 1.f64;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f64', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v13 = 1.F64;
+ static_assert(is_same<decltype(v13), const std::float64_t>::value, "");
+ static_assert(v13 == 1.F64, "");
+
+ static constexpr auto v14 = 1.e0f64;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f64', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v14 = 1.e0F64;
+ static_assert(is_same<decltype(v14), const std::float64_t>::value, "");
+ static_assert(v14 == 1.F64, "");
+
+ static constexpr auto v15 = 1.F64; // OK.
+ static_assert(is_same<decltype(v15), const std::float64_t>::value, "");
+ static_assert(v15 == 1.F64, "");
+
+ static constexpr auto v16 = 1.e0F64; // OK.
+ static_assert(is_same<decltype(v16), const std::float64_t>::value, "");
+ static_assert(v16 == 1.F64, "");
+#endif
+
+ // std::float128_t
+
+#if 0
+ static constexpr auto v17 = 1.f128;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f128', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v17 = 1.F128;
+ static_assert(is_same<decltype(v17), const std::float128_t>::value, "");
+ static_assert(v17 == 1.F128, "");
+
+ static constexpr auto v18 = 1.e0f128;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f128', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v18 = 1.e0F128;
+ static_assert(is_same<decltype(v18), const std::float128_t>::value, "");
+ static_assert(v18 == 1.F128, "");
+
+ static constexpr auto v19 = 1.F128; // OK.
+ static_assert(is_same<decltype(v19), const std::float128_t>::value, "");
+ static_assert(v19 == 1.F128, "");
+
+ static constexpr auto v20 = 1.e0F128; // OK.
+ static_assert(is_same<decltype(v20), const std::float128_t>::value, "");
+ static_assert(v20 == 1.F128, "");
+#endif
+}
+
+void hexadecimal_literals() {
+ // std::bfloat16_t
+
+#if 0
+ static constexpr auto v1 = 0xfp0bf16;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'bf16', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v1 = 0xfp0BF16;
+ static_assert(is_same<decltype(v1), const std::bfloat16_t>::value, "");
+ static_assert(v1 == 0xfp0BF16, "");
+
+ static constexpr auto v2 = 0xfp0BF16; // OK.
+ static_assert(is_same<decltype(v2), const std::bfloat16_t>::value, "");
+ static_assert(v2 == 0xfp0BF16, "");
+#endif
+
+ // _Float16/std::float16_t
+
+ static constexpr auto v3 = 0xfp0f16;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f16', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v3 = 0xfp0F16;
+ static_assert(is_same<decltype(v3), const _Float16>::value, "");
+ static_assert(v3 == 0xfp0F16, "");
+
+ static constexpr auto v4 = 0xfp0F16; // OK.
+ static_assert(is_same<decltype(v4), const _Float16>::value, "");
+ static_assert(v4 == 0xfp0F16, "");
+
+ // std::float32_t
+
+#if 0
+ static constexpr auto v5 = 0xfp0f32;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f32', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v5 = 0xfp0F32;
+ static_assert(is_same<decltype(v5), const std::float32_t>::value, "");
+ static_assert(v5 == 0xfp0F32, "");
+
+ static constexpr auto v6 = 0xfp0F32; // OK.
+ static_assert(is_same<decltype(v6), const std::float32_t>::value, "");
+ static_assert(v6 == 0xfp0F32, "");
+#endif
+
+ // std::float64_t
+
+#if 0
+ static constexpr auto v7 = 0xfp0f64;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f64', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v7 = 0xfp0F64;
+ static_assert(is_same<decltype(v7), const std::float64_t>::value, "");
+ static_assert(v7 == 0xfp0F64, "");
+
+ static constexpr auto v8 = 0xfp0F64; // OK.
+ static_assert(is_same<decltype(v8), const std::float64_t>::value, "");
+ static_assert(v8 == 0xfp0F64, "");
+#endif
+
+ // std::float128_t
+
+#if 0
+ static constexpr auto v9 = 0xfp0f128;
+ // DISABLED-CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f128', which is not uppercase
+ // DISABLED-CHECK-FIXES: static constexpr auto v9 = 0xfp0F128;
+ static_assert(is_same<decltype(v9), const std::float128_t>::value, "");
+ static_assert(v9 == 0xfp0F128, "");
+
+ static constexpr auto v10 = 0xfp0F128; // OK.
+ static_assert(is_same<decltype(v10), const std::float128_t>::value, "");
+ static_assert(v10 == 0xfp0F128, "");
+#endif
+
+}
+
+void size_t_suffix() {
+ // Signed
+
+ static constexpr auto v29 = 1z;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'z', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v29 = 1Z;
+ static_assert(v29 == 1Z, "");
+
+ static constexpr auto v30 = 1Z; // OK.
+ static_assert(v30 == 1Z, "");
+
+ // size_t Unsigned
+
+ static constexpr auto v31 = 1zu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'zu', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v31 = 1ZU;
+ static_assert(is_same<decltype(v31), const size_t>::value, "");
+ static_assert(v31 == 1ZU, "");
+
+ static constexpr auto v32 = 1Zu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Zu', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v32 = 1ZU;
+ static_assert(is_same<decltype(v32), const size_t>::value, "");
+ static_assert(v32 == 1ZU, "");
+
+ static constexpr auto v33 = 1zU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'zU', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v33 = 1ZU;
+ static_assert(is_same<decltype(v33), const size_t>::value, "");
+ static_assert(v33 == 1ZU, "");
+
+ static constexpr auto v34 = 1ZU; // OK.
+ static_assert(is_same<decltype(v34), const size_t>::value, "");
+ static_assert(v34 == 1ZU, "");
+
+ // Unsigned size_t
+
+ static constexpr auto v35 = 1uz;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'uz', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v35 = 1UZ;
+ static_assert(is_same<decltype(v35), const size_t>::value, "");
+ static_assert(v35 == 1UZ);
+
+ static constexpr auto v36 = 1uZ;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'uZ', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v36 = 1UZ;
+ static_assert(is_same<decltype(v36), const size_t>::value, "");
+ static_assert(v36 == 1UZ);
+
+ static constexpr auto v37 = 1Uz;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Uz', which is not uppercase
+ // CHECK-FIXES: static constexpr auto v37 = 1UZ;
+ static_assert(is_same<decltype(v37), const size_t>::value, "");
+ static_assert(v37 == 1UZ);
+
+ static constexpr auto v38 = 1UZ; // OK.
+ static_assert(is_same<decltype(v38), const size_t>::value, "");
+ static_assert(v38 == 1UZ);
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-float16.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-float16.cpp
deleted file mode 100644
index 46d7bc1..0000000
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-float16.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -target aarch64-linux-gnu -I %clang_tidy_headers
-
-#include "integral_constant.h"
-
-void float16_normal_literals() {
- // _Float16
-
- static constexpr auto v14 = 1.f16;
- // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f16', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1.f16;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F16{{$}}
- // CHECK-FIXES: static constexpr auto v14 = 1.F16;
- static_assert(is_same<decltype(v14), const _Float16>::value, "");
- static_assert(v14 == 1.F16, "");
-
- static constexpr auto v15 = 1.e0f16;
- // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f16', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1.e0f16;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F16{{$}}
- // CHECK-FIXES: static constexpr auto v15 = 1.e0F16;
- static_assert(is_same<decltype(v15), const _Float16>::value, "");
- static_assert(v15 == 1.F16, "");
-
- static constexpr auto v16 = 1.F16; // OK.
- static_assert(is_same<decltype(v16), const _Float16>::value, "");
- static_assert(v16 == 1.F16, "");
-
- static constexpr auto v17 = 1.e0F16; // OK.
- static_assert(is_same<decltype(v17), const _Float16>::value, "");
- static_assert(v17 == 1.F16, "");
-}
-
-void float16_hexadecimal_literals() {
-// _Float16
-
- static constexpr auto v13 = 0xfp0f16;
- // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f16', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v13 = 0xfp0f16;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F16{{$}}
- // CHECK-FIXES: static constexpr auto v13 = 0xfp0F16;
- static_assert(is_same<decltype(v13), const _Float16>::value, "");
- static_assert(v13 == 0xfp0F16, "");
-
- static constexpr auto v14 = 0xfp0F16; // OK.
- static_assert(is_same<decltype(v14), const _Float16>::value, "");
- static_assert(v14 == 0xfp0F16, "");
-
-}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point-opencl-half.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point-opencl-half.cpp
index ef905da..f644235 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point-opencl-half.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point-opencl-half.cpp
@@ -1,7 +1,4 @@
// RUN: %check_clang_tidy -std=cl2.0 %s readability-uppercase-literal-suffix %t -- -- -target x86_64-pc-linux-gnu -I %S -x cl
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -target x86_64-pc-linux-gnu -I %S -std=cl2.0 -x cl
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -target x86_64-pc-linux-gnu -I %S -std=cl2.0 -x cl
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
@@ -12,16 +9,10 @@ void floating_point_half_suffix() {
static half v2 = 1.h;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: floating point literal has suffix 'h', which is not uppercase
- // CHECK-MESSAGES-NEXT: static half v2 = 1.h;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: H{{$}}
// CHECK-HIXES: static half v2 = 1.H;
static half v3 = 1.e0h;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: floating point literal has suffix 'h', which is not uppercase
- // CHECK-MESSAGES-NEXT: static half v3 = 1.e0h;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: H{{$}}
// CHECK-HIXES: static half v3 = 1.e0H;
static half v4 = 1.H; // OK.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point.cpp
index d9f5bfb..fc1976b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-floating-point.cpp
@@ -1,7 +1,4 @@
// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers
#include "integral_constant.h"
@@ -18,18 +15,12 @@ void floating_point_suffix() {
static constexpr auto v2 = 1.f;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v2 = 1.f;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto v2 = 1.F;
static_assert(is_same<decltype(v2), const float>::value, "");
static_assert(v2 == 1.0F, "");
static constexpr auto v3 = 1.e0f;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 1.e0f;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto v3 = 1.e0F;
static_assert(is_same<decltype(v3), const float>::value, "");
static_assert(v3 == 1.0F, "");
@@ -46,18 +37,12 @@ void floating_point_suffix() {
static constexpr auto v6 = 1.l;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'l', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v6 = 1.l;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: L{{$}}
// CHECK-FIXES: static constexpr auto v6 = 1.L;
static_assert(is_same<decltype(v6), const long double>::value, "");
static_assert(v6 == 1., "");
static constexpr auto v7 = 1.e0l;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'l', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1.e0l;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: L{{$}}
// CHECK-FIXES: static constexpr auto v7 = 1.e0L;
static_assert(is_same<decltype(v7), const long double>::value, "");
static_assert(v7 == 1., "");
@@ -74,18 +59,12 @@ void floating_point_suffix() {
static constexpr auto v10 = 1.q;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'q', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v10 = 1.q;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: Q{{$}}
// CHECK-FIXES: static constexpr auto v10 = 1.Q;
static_assert(is_same<decltype(v10), const __float128>::value, "");
static_assert(v10 == 1., "");
static constexpr auto v11 = 1.e0q;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'q', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v11 = 1.e0q;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: Q{{$}}
// CHECK-FIXES: static constexpr auto v11 = 1.e0Q;
static_assert(is_same<decltype(v11), const __float128>::value, "");
static_assert(v11 == 1., "");
@@ -104,18 +83,12 @@ void floating_point_complex_suffix() {
static constexpr auto v14 = 1.i;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'i', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1.i;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: I{{$}}
// CHECK-FIXES: static constexpr auto v14 = 1.I;
static_assert(is_same<decltype(v14), const _Complex double>::value, "");
static_assert(v14 == 1.I, "");
static constexpr auto v15 = 1.e0i;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'i', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1.e0i;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: I{{$}}
// CHECK-FIXES: static constexpr auto v15 = 1.e0I;
static_assert(is_same<decltype(v15), const _Complex double>::value, "");
static_assert(v15 == 1.I, "");
@@ -132,18 +105,12 @@ void floating_point_complex_suffix() {
static constexpr auto v18 = 1.j;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'j', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v18 = 1.j;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: J{{$}}
// CHECK-FIXES: static constexpr auto v18 = 1.J;
static_assert(is_same<decltype(v18), const _Complex double>::value, "");
static_assert(v18 == 1.J, "");
static constexpr auto v19 = 1.e0j;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'j', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v19 = 1.e0j;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: J{{$}}
// CHECK-FIXES: static constexpr auto v19 = 1.e0J;
static_assert(is_same<decltype(v19), const _Complex double>::value, "");
static_assert(v19 == 1.J, "");
@@ -161,9 +128,6 @@ void macros() {
#define PASSTHROUGH(X) X
static constexpr auto m0 = PASSTHROUGH(1.f);
// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto m0 = PASSTHROUGH(1.f);
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto m0 = PASSTHROUGH(1.F);
static_assert(is_same<decltype(m0), const float>::value, "");
static_assert(m0 == 1.0F, "");
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-hexadecimal-floating-point.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-hexadecimal-floating-point.cpp
index 7207715..9bb1cee 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-hexadecimal-floating-point.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-hexadecimal-floating-point.cpp
@@ -1,7 +1,4 @@
// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers
#include "integral_constant.h"
@@ -14,9 +11,6 @@ void floating_point_suffix() {
static constexpr auto v1 = 0xfp0f;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v1 = 0xfp0f;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto v1 = 0xfp0F;
static_assert(is_same<decltype(v1), const float>::value, "");
static_assert(v1 == 15, "");
@@ -27,9 +21,6 @@ void floating_point_suffix() {
static constexpr auto v3 = 0xfP0f;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 0xfP0f;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto v3 = 0xfP0F;
static_assert(is_same<decltype(v3), const float>::value, "");
static_assert(v3 == 15, "");
@@ -40,9 +31,6 @@ void floating_point_suffix() {
static constexpr auto v5 = 0xFP0f;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 0xFP0f;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto v5 = 0xFP0F;
static_assert(is_same<decltype(v5), const float>::value, "");
static_assert(v5 == 15, "");
@@ -53,9 +41,6 @@ void floating_point_suffix() {
static constexpr auto v7 = 0xFp0f;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 0xFp0f;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto v7 = 0xFp0F;
static_assert(is_same<decltype(v7), const float>::value, "");
static_assert(v7 == 15, "");
@@ -68,9 +53,6 @@ void floating_point_suffix() {
static constexpr auto v9 = 0xfp0l;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'l', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v9 = 0xfp0l;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: L{{$}}
// CHECK-FIXES: static constexpr auto v9 = 0xfp0L;
static_assert(is_same<decltype(v9), const long double>::value, "");
static_assert(v9 == 0xfp0, "");
@@ -83,9 +65,6 @@ void floating_point_suffix() {
static constexpr auto v11 = 0xfp0q;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'q', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v11 = 0xfp0q;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: Q{{$}}
// CHECK-FIXES: static constexpr auto v11 = 0xfp0Q;
static_assert(is_same<decltype(v11), const __float128>::value, "");
static_assert(v11 == 0xfp0, "");
@@ -100,9 +79,6 @@ void floating_point_complex_suffix() {
static constexpr auto v14 = 0xfp0i;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'i', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 0xfp0i;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: I{{$}}
// CHECK-FIXES: static constexpr auto v14 = 0xfp0I;
static_assert(is_same<decltype(v14), const _Complex double>::value, "");
static_assert(v14 == 0xfp0I, "");
@@ -115,9 +91,6 @@ void floating_point_complex_suffix() {
static constexpr auto v18 = 0xfp0j;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'j', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v18 = 0xfp0j;
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: J{{$}}
// CHECK-FIXES: static constexpr auto v18 = 0xfp0J;
static_assert(is_same<decltype(v18), const _Complex double>::value, "");
static_assert(v18 == 0xfp0J, "");
@@ -131,9 +104,6 @@ void macros() {
#define PASSTHROUGH(X) X
static constexpr auto m0 = PASSTHROUGH(0x0p0f);
// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: floating point literal has suffix 'f', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto m0 = PASSTHROUGH(0x0p0f);
- // CHECK-MESSAGES-NEXT: ^ ~
- // CHECK-MESSAGES-NEXT: F{{$}}
// CHECK-FIXES: static constexpr auto m0 = PASSTHROUGH(0x0p0F);
static_assert(is_same<decltype(m0), const float>::value, "");
static_assert(m0 == 0x0p0F, "");
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-custom-list.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-custom-list.cpp
index 3215075..a4fcf3a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-custom-list.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-custom-list.cpp
@@ -1,7 +1,4 @@
// RUN: %check_clang_tidy --match-partial-fixes %s readability-uppercase-literal-suffix %t -- -config="{CheckOptions: {readability-uppercase-literal-suffix.NewSuffixes: 'L;uL'}}" -- -I %clang_tidy_headers
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -config="{CheckOptions: {readability-uppercase-literal-suffix.NewSuffixes: 'L;uL'}}" -- -I %clang_tidy_headers
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -config="{CheckOptions: {readability-uppercase-literal-suffix.NewSuffixes: 'L;uL'}}" -- -I %clang_tidy_headers
#include "integral_constant.h"
@@ -20,9 +17,6 @@ void integer_suffix() {
static constexpr auto v5 = 1l;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'l', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 1l;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: L{{$}}
// CHECK-FIXES: static constexpr auto v5 = 1L;
static_assert(is_same<decltype(v5), const long>::value, "");
static_assert(v5 == 1, "");
@@ -45,9 +39,6 @@ void integer_suffix() {
static constexpr auto v9 = 1ul;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'ul', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v9 = 1ul;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: uL{{$}}
// CHECK-FIXES: static constexpr auto v9 = 1uL;
static_assert(is_same<decltype(v9), const unsigned long>::value, "");
static_assert(v9 == 1, "");
@@ -58,18 +49,12 @@ void integer_suffix() {
static constexpr auto v11 = 1Ul;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Ul', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v11 = 1Ul;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: uL{{$}}
// CHECK-FIXES: static constexpr auto v11 = 1uL;
static_assert(is_same<decltype(v11), const unsigned long>::value, "");
static_assert(v11 == 1, "");
static constexpr auto v12 = 1UL; // OK.
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'UL', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v12 = 1UL;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: uL{{$}}
// CHECK-FIXES: static constexpr auto v12 = 1uL;
static_assert(is_same<decltype(v12), const unsigned long>::value, "");
static_assert(v12 == 1, "");
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-ms.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-ms.cpp
index 7ac4a75..7462818 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-ms.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer-ms.cpp
@@ -1,14 +1,9 @@
// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers -fms-extensions
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers -fms-extensions
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -target x86_64-pc-linux-gnu -I %clang_tidy_headers -fms-extensions
#include "integral_constant.h"
void integer_suffix() {
static constexpr auto v0 = __LINE__; // synthetic
- static_assert(v0 == 9 || v0 == 5, "");
-
static constexpr auto v1 = __cplusplus; // synthetic, long
static constexpr auto v2 = 1; // no literal
@@ -19,9 +14,6 @@ void integer_suffix() {
static constexpr auto v3 = 1i32;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i32', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 1i32;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: I32{{$}}
// CHECK-FIXES: static constexpr auto v3 = 1I32;
static_assert(is_same<decltype(v3), const int>::value, "");
static_assert(v3 == 1I32, "");
@@ -34,9 +26,6 @@ void integer_suffix() {
static constexpr auto v5 = 1i64;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i64', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 1i64;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: I64{{$}}
// CHECK-FIXES: static constexpr auto v5 = 1I64;
static_assert(is_same<decltype(v5), const long int>::value, "");
static_assert(v5 == 1I64, "");
@@ -49,9 +38,6 @@ void integer_suffix() {
static constexpr auto v7 = 1i16;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i16', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1i16;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: I16{{$}}
// CHECK-FIXES: static constexpr auto v7 = 1I16;
static_assert(is_same<decltype(v7), const short>::value, "");
static_assert(v7 == 1I16, "");
@@ -64,9 +50,6 @@ void integer_suffix() {
static constexpr auto v9 = 1i8;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i8', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v9 = 1i8;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: I8{{$}}
// CHECK-FIXES: static constexpr auto v9 = 1I8;
static_assert(is_same<decltype(v9), const char>::value, "");
static_assert(v9 == 1I8, "");
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer.cpp
index 084d9f6..e4dd968 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/uppercase-literal-suffix-integer.cpp
@@ -1,14 +1,10 @@
// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -I %clang_tidy_headers
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -I %clang_tidy_headers
-// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -I %clang_tidy_headers
#include "integral_constant.h"
+#include <cstddef>
void integer_suffix() {
static constexpr auto v0 = __LINE__; // synthetic
- static_assert(v0 == 9 || v0 == 5, "");
-
static constexpr auto v1 = __cplusplus; // synthetic, long
static constexpr auto v2 = 1; // no literal
@@ -19,9 +15,6 @@ void integer_suffix() {
static constexpr auto v3 = 1u;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'u', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 1u;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: U{{$}}
// CHECK-FIXES: static constexpr auto v3 = 1U;
static_assert(is_same<decltype(v3), const unsigned int>::value, "");
static_assert(v3 == 1, "");
@@ -34,9 +27,6 @@ void integer_suffix() {
static constexpr auto v5 = 1l;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'l', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 1l;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: L{{$}}
// CHECK-FIXES: static constexpr auto v5 = 1L;
static_assert(is_same<decltype(v5), const long>::value, "");
static_assert(v5 == 1, "");
@@ -49,9 +39,6 @@ void integer_suffix() {
static constexpr auto v7 = 1ll;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'll', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1ll;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: LL{{$}}
// CHECK-FIXES: static constexpr auto v7 = 1LL;
static_assert(is_same<decltype(v7), const long long>::value, "");
static_assert(v7 == 1, "");
@@ -64,27 +51,18 @@ void integer_suffix() {
static constexpr auto v9 = 1ul;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'ul', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v9 = 1ul;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: UL{{$}}
// CHECK-FIXES: static constexpr auto v9 = 1UL;
static_assert(is_same<decltype(v9), const unsigned long>::value, "");
static_assert(v9 == 1, "");
static constexpr auto v10 = 1uL;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'uL', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v10 = 1uL;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: UL{{$}}
// CHECK-FIXES: static constexpr auto v10 = 1UL;
static_assert(is_same<decltype(v10), const unsigned long>::value, "");
static_assert(v10 == 1, "");
static constexpr auto v11 = 1Ul;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Ul', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v11 = 1Ul;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: UL{{$}}
// CHECK-FIXES: static constexpr auto v11 = 1UL;
static_assert(is_same<decltype(v11), const unsigned long>::value, "");
static_assert(v11 == 1, "");
@@ -97,27 +75,18 @@ void integer_suffix() {
static constexpr auto v13 = 1lu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v13 = 1lu;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: LU{{$}}
// CHECK-FIXES: static constexpr auto v13 = 1LU;
static_assert(is_same<decltype(v13), const unsigned long>::value, "");
static_assert(v13 == 1, "");
static constexpr auto v14 = 1Lu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Lu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1Lu;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: LU{{$}}
// CHECK-FIXES: static constexpr auto v14 = 1LU;
static_assert(is_same<decltype(v14), const unsigned long>::value, "");
static_assert(v14 == 1, "");
static constexpr auto v15 = 1lU;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lU', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1lU;
- // CHECK-MESSAGES-NEXT: ^~~
- // CHECK-MESSAGES-NEXT: LU{{$}}
// CHECK-FIXES: static constexpr auto v15 = 1LU;
static_assert(is_same<decltype(v15), const unsigned long>::value, "");
static_assert(v15 == 1, "");
@@ -130,27 +99,18 @@ void integer_suffix() {
static constexpr auto v17 = 1ull;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'ull', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v17 = 1ull;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: ULL{{$}}
// CHECK-FIXES: static constexpr auto v17 = 1ULL;
static_assert(is_same<decltype(v17), const unsigned long long>::value, "");
static_assert(v17 == 1, "");
static constexpr auto v18 = 1uLL;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'uLL', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v18 = 1uLL;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: ULL{{$}}
// CHECK-FIXES: static constexpr auto v18 = 1ULL;
static_assert(is_same<decltype(v18), const unsigned long long>::value, "");
static_assert(v18 == 1, "");
static constexpr auto v19 = 1Ull;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Ull', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v19 = 1Ull;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: ULL{{$}}
// CHECK-FIXES: static constexpr auto v19 = 1ULL;
static_assert(is_same<decltype(v19), const unsigned long long>::value, "");
static_assert(v19 == 1, "");
@@ -163,27 +123,18 @@ void integer_suffix() {
static constexpr auto v21 = 1llu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v21 = 1llu;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: LLU{{$}}
// CHECK-FIXES: static constexpr auto v21 = 1LLU;
static_assert(is_same<decltype(v21), const unsigned long long>::value, "");
static_assert(v21 == 1, "");
static constexpr auto v22 = 1LLu;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'LLu', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v22 = 1LLu;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: LLU{{$}}
// CHECK-FIXES: static constexpr auto v22 = 1LLU;
static_assert(is_same<decltype(v22), const unsigned long long>::value, "");
static_assert(v22 == 1, "");
static constexpr auto v23 = 1llU;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llU', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v23 = 1llU;
- // CHECK-MESSAGES-NEXT: ^~~~
- // CHECK-MESSAGES-NEXT: LLU{{$}}
// CHECK-FIXES: static constexpr auto v23 = 1LLU;
static_assert(is_same<decltype(v23), const unsigned long long>::value, "");
static_assert(v23 == 1, "");
@@ -198,9 +149,6 @@ void integer_complex_suffix() {
static constexpr auto v25 = 1i;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'i', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v25 = 1i;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: I{{$}}
// CHECK-FIXES: static constexpr auto v25 = 1I;
static_assert(is_same<decltype(v25), const _Complex int>::value, "");
static_assert(v25 == 1I, "");
@@ -213,9 +161,6 @@ void integer_complex_suffix() {
static constexpr auto v27 = 1j;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'j', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto v27 = 1j;
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: J{{$}}
// CHECK-FIXES: static constexpr auto v27 = 1J;
static_assert(is_same<decltype(v27), const _Complex int>::value, "");
static_assert(v27 == 1J, "");
@@ -229,9 +174,6 @@ void macros() {
#define PASSTHROUGH(X) X
static constexpr auto m0 = PASSTHROUGH(1u);
// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: integer literal has suffix 'u', which is not uppercase
- // CHECK-MESSAGES-NEXT: static constexpr auto m0 = PASSTHROUGH(1u);
- // CHECK-MESSAGES-NEXT: ^~
- // CHECK-MESSAGES-NEXT: U{{$}}
// CHECK-FIXES: static constexpr auto m0 = PASSTHROUGH(1U);
static_assert(is_same<decltype(m0), const unsigned int>::value, "");
static_assert(m0 == 1, "");
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp
index 7efa7d0..58f3b23 100644
--- a/clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp
@@ -10,7 +10,7 @@
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s
-// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER --allow-empty %s
// Check that `-header-filter` operates on the same file paths as paths in
// diagnostics printed by ClangTidy.
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp
index 448ef9d..d9ec104 100644
--- a/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp
@@ -66,19 +66,14 @@ class A { A(int); };
// CHECK4-NOT: warning:
// CHECK4-QUIET-NOT: warning:
-// CHECK: Suppressed 3 warnings (3 in non-user code)
// CHECK: Use -header-filter=.* to display errors from all non-system headers.
// CHECK-QUIET-NOT: Suppressed
-// CHECK2: Suppressed 1 warnings (1 in non-user code)
-// CHECK2: Use -header-filter=.* {{.*}}
// CHECK2-QUIET-NOT: Suppressed
-// CHECK3: Suppressed 2 warnings (2 in non-user code)
// CHECK3: Use -header-filter=.* {{.*}}
// CHECK3-QUIET-NOT: Suppressed
// CHECK4-NOT: Suppressed {{.*}} warnings
// CHECK4-NOT: Use -header-filter=.* {{.*}}
// CHECK4-QUIET-NOT: Suppressed
-// CHECK6: Suppressed 2 warnings (2 in non-user code)
// CHECK6: Use -header-filter=.* {{.*}}
int x = 123;
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/quiet-flag.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/quiet-flag.cpp
new file mode 100644
index 0000000..0ed6d01
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/quiet-flag.cpp
@@ -0,0 +1,26 @@
+// This test ensures that the --quiet flag only suppresses the "X warnings generated"
+// message while keeping all diagnostic information including caret indicators (^).
+
+// RUN: clang-tidy -checks=-*,readability-magic-numbers,clang-diagnostic-sign-compare %s -- \
+// RUN: -Wsign-compare 2>&1 | FileCheck %s --check-prefix=CHECK-NORMAL
+// RUN: clang-tidy -checks=-*,readability-magic-numbers,clang-diagnostic-sign-compare -quiet %s -- \
+// RUN: -Wsign-compare 2>&1 | FileCheck %s --check-prefix=CHECK-QUIET
+
+// CHECK-NORMAL: 2 warnings generated
+// CHECK-NORMAL-DAG: warning: 42 is a magic number
+// CHECK-NORMAL-DAG: {{[ ]*\^}}
+// CHECK-NORMAL-DAG: warning: comparison of integers of different signs
+// CHECK-NORMAL-DAG: {{[ ]*~ \^ ~}}
+
+// CHECK-QUIET-NOT: {{[0-9]+}} warning{{s?}} generated
+// CHECK-QUIET-DAG: warning: 42 is a magic number
+// CHECK-QUIET-DAG: {{[ ]*\^}}
+// CHECK-QUIET-DAG: warning: comparison of integers of different signs
+// CHECK-QUIET-DAG: {{[ ]*~ \^ ~}}
+
+int main() {
+ const int CONST_VAL = 10;
+ int x = 42; // trigger 'readability-magic-numbers' with caret: ^
+ unsigned int y = CONST_VAL;
+ return x < y; // trigger 'clang-diagnostic-sign-compare' with caret: ^
+}
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/system-headers.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/system-headers.cpp
index 9fa990b..a25480e 100644
--- a/clang-tools-extra/test/clang-tidy/infrastructure/system-headers.cpp
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/system-headers.cpp
@@ -11,9 +11,9 @@
// RUN: clang-tidy -help | FileCheck -check-prefix=CHECK-OPT-PRESENT %s
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers=true %s -- -isystem %S/Inputs/system-headers 2>&1 | FileCheck -check-prefix=CHECK-SYSTEM-HEADERS %s
-// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers=false %s -- -isystem %S/Inputs/system-headers 2>&1 | FileCheck -check-prefix=CHECK-NO-SYSTEM-HEADERS %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers=false %s -- -isystem %S/Inputs/system-headers 2>&1 | FileCheck -check-prefix=CHECK-NO-SYSTEM-HEADERS --allow-empty %s
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -config='SystemHeaders: true' %s -- -isystem %S/Inputs/system-headers 2>&1 | FileCheck -check-prefix=CHECK-SYSTEM-HEADERS %s
-// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -config='SystemHeaders: false' %s -- -isystem %S/Inputs/system-headers 2>&1 | FileCheck -check-prefix=CHECK-NO-SYSTEM-HEADERS %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -config='SystemHeaders: false' %s -- -isystem %S/Inputs/system-headers 2>&1 | FileCheck -check-prefix=CHECK-NO-SYSTEM-HEADERS --allow-empty %s
#include <system_header.h>
// CHECK-SYSTEM-HEADERS: system_header.h:1:13: warning: single-argument constructors must be marked explicit