55 AnalyzePointers(Options.get(
"AnalyzePointers", true)),
56 AnalyzeReferences(Options.get(
"AnalyzeReferences", true)),
57 AnalyzeValues(Options.get(
"AnalyzeValues", true)),
58 AnalyzeParameters(Options.get(
"AnalyzeParameters", true)),
60 WarnPointersAsPointers(Options.get(
"WarnPointersAsPointers", true)),
61 WarnPointersAsValues(Options.get(
"WarnPointersAsValues", false)),
63 TransformPointersAsPointers(
64 Options.get(
"TransformPointersAsPointers", true)),
65 TransformPointersAsValues(
66 Options.get(
"TransformPointersAsValues", false)),
67 TransformReferences(Options.get(
"TransformReferences", true)),
68 TransformValues(Options.get(
"TransformValues", true)),
71 utils::options::parseStringList(Options.get(
"AllowedTypes",
""))) {
72 if (AnalyzeValues ==
false && AnalyzeReferences ==
false &&
73 AnalyzePointers ==
false)
74 this->configurationDiag(
75 "The check 'misc-const-correctness' will not "
76 "perform any analysis because 'AnalyzeValues', "
77 "'AnalyzeReferences' and 'AnalyzePointers' are false.");
100 const auto ConstType =
101 hasType(qualType(isConstQualified(),
103 unless(pointerType())));
105 const auto ConstReference = hasType(references(isConstQualified()));
106 const auto RValueReference = hasType(
107 referenceType(anyOf(rValueReferenceType(), unless(isSpelledAsLValue()))));
109 const auto TemplateType = anyOf(
110 hasType(hasCanonicalType(templateTypeParmType())),
111 hasType(substTemplateTypeParmType()), hasType(isDependentType()),
114 hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))),
115 hasType(referenceType(pointee(substTemplateTypeParmType()))));
117 auto AllowedTypeDecl = namedDecl(anyOf(
120 const auto AllowedType = hasType(qualType(
121 anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl),
122 pointerType(pointee(hasDeclaration(AllowedTypeDecl))))));
124 const auto AutoTemplateType = varDecl(
125 anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))),
126 hasType(pointerType(pointee(autoType())))));
128 const auto FunctionPointerRef =
129 hasType(hasCanonicalType(referenceType(pointee(functionType()))));
131 const auto CommonExcludeTypes =
132 anyOf(ConstType, ConstReference, RValueReference, TemplateType,
133 FunctionPointerRef, hasType(cxxRecordDecl(isLambda())),
134 AutoTemplateType, isImplicit(), AllowedType);
138 const auto LocalValDecl =
139 varDecl(isLocal(), hasInitializer(unless(isInstantiationDependent())),
140 unless(CommonExcludeTypes));
144 const auto FunctionScope =
145 functionDecl(hasBody(stmt(forEachDescendant(
146 declStmt(containsAnyDeclaration(
147 LocalValDecl.bind(
"value")),
148 unless(has(decompositionDecl())))
151 .bind(
"function-decl");
153 Finder->addMatcher(FunctionScope,
this);
155 if (AnalyzeParameters) {
156 const auto ParamMatcher =
157 parmVarDecl(unless(CommonExcludeTypes), unless(isUnnamed()),
158 anyOf(hasType(referenceType()), hasType(pointerType())))
163 const auto FunctionWithParams =
165 hasBody(stmt().bind(
"scope")), has(typeLoc(forEach(ParamMatcher))),
166 unless(cxxMethodDecl()), unless(isFunctionTemplateSpecialization()),
167 unless(isTemplate()))
168 .bind(
"function-decl");
170 Finder->addMatcher(FunctionWithParams,
this);
175 const FunctionDecl *Function, ASTContext &Context,
176 Qualifiers::TQ Qualifier,
181 if (
const auto *ParamDecl = dyn_cast<ParmVarDecl>(Variable)) {
182 const unsigned ParamIdx = ParamDecl->getFunctionScopeIndex();
185 Function->redecls(), [ParamIdx](
const FunctionDecl *Redecl) {
186 const QualType Type = Redecl->getParamDecl(ParamIdx)->getType();
187 return Type->isTypedefNameType() || Type->getAs<UsingType>();
191 for (
const FunctionDecl *Redecl : Function->redecls()) {
192 Diag << addQualifierToVarDecl(*Redecl->getParamDecl(ParamIdx), Context,
193 Qualifier, Target, Policy);
196 Diag << addQualifierToVarDecl(*Variable, Context, Qualifier, Target,
209 const auto *LocalScope = Result.Nodes.getNodeAs<Stmt>(
"scope");
210 const auto *Variable = Result.Nodes.getNodeAs<VarDecl>(
"value");
211 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(
"function-decl");
212 const auto *VarDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
"decl-stmt");
214 assert(Variable && LocalScope && Function);
220 const bool CanBeFixIt = isa<ParmVarDecl>(Variable) ||
221 (VarDeclStmt && VarDeclStmt->isSingleDecl());
228 bool IsNormalVariableInTemplate = Function->isTemplateInstantiation();
229 if (IsNormalVariableInTemplate &&
230 TemplateDiagnosticsCache.contains(Variable->getBeginLoc()))
233 VariableCategory VC = VariableCategory::Value;
234 const QualType VT = Variable->getType();
235 if (VT->isReferenceType()) {
236 VC = VariableCategory::Reference;
237 }
else if (VT->isPointerType()) {
238 VC = VariableCategory::Pointer;
239 }
else if (
const auto *ArrayT = dyn_cast<ArrayType>(VT)) {
240 if (ArrayT->getElementType()->isPointerType())
241 VC = VariableCategory::Pointer;
244 auto CheckValue = [&]() {
246 if (isMutated(Variable, LocalScope, Function, Result.Context))
249 auto Diag = diag(Variable->getBeginLoc(),
250 "variable %0 of type %1 can be declared 'const'")
252 if (IsNormalVariableInTemplate)
253 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
258 if (VC == VariableCategory::Value && TransformValues) {
260 Qualifiers::Const, QualifierTarget::Value,
261 QualifierPolicy::Right);
267 if (VC == VariableCategory::Reference && TransformReferences) {
269 Qualifiers::Const, QualifierTarget::Value,
270 QualifierPolicy::Right);
274 if (VC == VariableCategory::Pointer && TransformPointersAsValues) {
276 Qualifiers::Const, QualifierTarget::Value,
277 QualifierPolicy::Right);
282 auto CheckPointee = [&]() {
283 assert(VC == VariableCategory::Pointer);
284 registerScope(LocalScope, Result.Context);
285 if (ScopesCache[LocalScope]->isPointeeMutated(Variable))
288 diag(Variable->getBeginLoc(),
289 "pointee of variable %0 of type %1 can be declared 'const'")
291 if (IsNormalVariableInTemplate)
292 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
296 if (TransformPointersAsPointers) {
298 Qualifiers::Const, QualifierTarget::Pointee,
299 QualifierPolicy::Right);
305 if (VC == VariableCategory::Value && AnalyzeValues) {
309 if (VC == VariableCategory::Reference && AnalyzeReferences) {
310 if (VT->getPointeeType()->isPointerType() && !WarnPointersAsValues)
315 if (VC == VariableCategory::Pointer && AnalyzePointers) {
316 if (WarnPointersAsValues && !VT.isConstQualified())
318 if (WarnPointersAsPointers) {
319 if (
const auto *PT = dyn_cast<PointerType>(VT)) {
320 if (!PT->getPointeeType().isConstQualified() &&
321 !PT->getPointeeType()->isFunctionType())
324 if (
const auto *AT = dyn_cast<ArrayType>(VT)) {
325 assert(AT->getElementType()->isPointerType());
326 if (!AT->getElementType()->getPointeeType().isConstQualified())
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.