61 AnalyzePointers(Options.get(
"AnalyzePointers", true)),
62 AnalyzeReferences(Options.get(
"AnalyzeReferences", true)),
63 AnalyzeValues(Options.get(
"AnalyzeValues", true)),
64 AnalyzeAutoVariables(Options.get(
"AnalyzeAutoVariables", true)),
65 AnalyzeLambdas(Options.get(
"AnalyzeLambdas", true)),
66 AnalyzeParameters(Options.get(
"AnalyzeParameters", true)),
68 WarnPointersAsPointers(Options.get(
"WarnPointersAsPointers", true)),
69 WarnPointersAsValues(Options.get(
"WarnPointersAsValues", false)),
71 TransformPointersAsPointers(
72 Options.get(
"TransformPointersAsPointers", true)),
73 TransformPointersAsValues(
74 Options.get(
"TransformPointersAsValues", false)),
75 TransformReferences(Options.get(
"TransformReferences", true)),
76 TransformValues(Options.get(
"TransformValues", true)),
79 utils::options::parseStringList(Options.get(
"AllowedTypes",
""))) {
80 if (AnalyzeValues ==
false && AnalyzeReferences ==
false &&
81 AnalyzePointers ==
false)
82 this->configurationDiag(
83 "The check 'misc-const-correctness' will not "
84 "perform any analysis because 'AnalyzeValues', "
85 "'AnalyzeReferences' and 'AnalyzePointers' are false.");
87 if (AnalyzeLambdas && !AnalyzeAutoVariables)
88 this->configurationDiag(
"The check 'misc-const-correctness' will not "
89 "analyze lambdas because 'AnalyzeLambdas' has no "
90 "effect while 'AnalyzeAutoVariables' is false.");
115 const auto ConstType =
116 hasType(qualType(isConstQualified(),
118 unless(pointerType())));
120 const auto ConstReference = hasType(references(isConstQualified()));
121 const auto RValueReference = hasType(
122 referenceType(anyOf(rValueReferenceType(), unless(isSpelledAsLValue()))));
124 const auto TemplateType = anyOf(
125 hasType(hasCanonicalType(templateTypeParmType())),
126 hasType(substTemplateTypeParmType()), hasType(isDependentType()),
129 hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))),
130 hasType(referenceType(pointee(substTemplateTypeParmType()))));
132 const auto AllowedTypeDecl = namedDecl(anyOf(
135 const auto AllowedType = hasType(qualType(
136 anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl),
137 pointerType(pointee(hasDeclaration(AllowedTypeDecl))))));
139 const auto AutoTemplateType = varDecl(
140 anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))),
141 hasType(pointerType(pointee(autoType())))));
143 const auto FunctionPointerRef =
144 hasType(hasCanonicalType(referenceType(pointee(functionType()))));
147 const auto DecltypeAutoType =
148 hasType(ignoringParens(autoType(isDecltypeAuto())));
150 const auto CommonExcludeTypes =
151 anyOf(ConstType, ConstReference, RValueReference, TemplateType,
152 FunctionPointerRef, hasType(cxxRecordDecl(isLambda())),
153 AutoTemplateType, isImplicit(), AllowedType);
157 const auto LocalValDecl = varDecl(
158 isLocal(), hasInitializer(anything()),
159 unless(anyOf(ConstType, ConstReference, TemplateType,
160 hasInitializer(isInstantiationDependent()), RValueReference,
161 FunctionPointerRef, isImplicit(), AllowedType,
164 ? Matcher<VarDecl>(anything())
165 : Matcher<VarDecl>(unless(hasType(cxxRecordDecl(isLambda())))),
167 ? Matcher<VarDecl>(anything())
168 : Matcher<VarDecl>(unless(hasTypeLoc(hasContainedAutoType()))));
172 const auto FunctionScope =
173 functionDecl(hasBody(stmt(forEachDescendant(
174 declStmt(containsAnyDeclaration(
175 LocalValDecl.bind(
"value")),
176 unless(has(decompositionDecl())))
179 .bind(
"function-decl");
181 Finder->addMatcher(FunctionScope,
this);
183 if (AnalyzeParameters) {
184 const auto ParamMatcher =
185 parmVarDecl(unless(CommonExcludeTypes), unless(isUnnamed()),
186 anyOf(hasType(referenceType()), hasType(pointerType())))
191 const auto FunctionWithParams =
193 hasBody(stmt().bind(
"scope")), has(typeLoc(forEach(ParamMatcher))),
194 unless(cxxMethodDecl()), unless(isFunctionTemplateSpecialization()),
195 unless(isTemplate()))
196 .bind(
"function-decl");
198 Finder->addMatcher(FunctionWithParams,
this);
203 const VarDecl *Variable,
204 const FunctionDecl *Function,
205 const ASTContext &Context, Qualifiers::TQ Qualifier,
210 if (
const auto *ParamDecl = dyn_cast<ParmVarDecl>(Variable)) {
211 const unsigned ParamIdx = ParamDecl->getFunctionScopeIndex();
214 Function->redecls(), [ParamIdx](
const FunctionDecl *Redecl) {
215 const QualType Type = Redecl->getParamDecl(ParamIdx)->getType();
216 return Type->isTypedefNameType() || Type->getAs<UsingType>();
220 for (
const FunctionDecl *Redecl : Function->redecls()) {
221 Diag << addQualifierToVarDecl(*Redecl->getParamDecl(ParamIdx), Context,
222 Qualifier, Target, Policy);
225 Diag << addQualifierToVarDecl(*Variable, Context, Qualifier, Target,
238 const auto *LocalScope = Result.Nodes.getNodeAs<Stmt>(
"scope");
239 const auto *Variable = Result.Nodes.getNodeAs<VarDecl>(
"value");
240 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(
"function-decl");
241 const auto *VarDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
"decl-stmt");
243 assert(Variable && LocalScope && Function);
249 const bool CanBeFixIt = isa<ParmVarDecl>(Variable) ||
250 (VarDeclStmt && VarDeclStmt->isSingleDecl());
257 bool IsNormalVariableInTemplate = Function->isTemplateInstantiation();
258 if (IsNormalVariableInTemplate &&
259 TemplateDiagnosticsCache.contains(Variable->getBeginLoc()))
262 VariableCategory VC = VariableCategory::Value;
263 const QualType VT = Variable->getType();
264 if (VT->isReferenceType())
265 VC = VariableCategory::Reference;
266 else if (VT->isPointerType())
267 VC = VariableCategory::Pointer;
268 else if (
const auto *ArrayT = dyn_cast<ArrayType>(VT);
269 ArrayT && ArrayT->getElementType()->isPointerType())
270 VC = VariableCategory::Pointer;
272 const auto CheckValue = [&]() {
274 if (isMutated(Variable, LocalScope, Function, Result.Context))
277 const auto Diag = diag(Variable->getBeginLoc(),
278 "variable %0 of type %1 can be declared 'const'")
280 if (IsNormalVariableInTemplate)
281 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
286 if (VC == VariableCategory::Value && TransformValues) {
288 Qualifiers::Const, QualifierTarget::Value,
289 QualifierPolicy::Right);
295 if (VC == VariableCategory::Reference && TransformReferences) {
297 Qualifiers::Const, QualifierTarget::Value,
298 QualifierPolicy::Right);
302 if (VC == VariableCategory::Pointer && TransformPointersAsValues) {
304 Qualifiers::Const, QualifierTarget::Value,
305 QualifierPolicy::Right);
310 const auto CheckPointee = [&]() {
311 assert(VC == VariableCategory::Pointer);
312 registerScope(LocalScope, Result.Context);
313 if (ScopesCache[LocalScope]->isPointeeMutated(Variable))
316 diag(Variable->getBeginLoc(),
317 "pointee of variable %0 of type %1 can be declared 'const'")
319 if (IsNormalVariableInTemplate)
320 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
324 if (TransformPointersAsPointers) {
326 Qualifiers::Const, QualifierTarget::Pointee,
327 QualifierPolicy::Right);
333 if (VC == VariableCategory::Value && AnalyzeValues) {
337 if (VC == VariableCategory::Reference && AnalyzeReferences) {
338 if (VT->getPointeeType()->isPointerType() && !WarnPointersAsValues)
343 if (VC == VariableCategory::Pointer && AnalyzePointers) {
344 if (WarnPointersAsValues && !VT.isConstQualified())
346 if (WarnPointersAsPointers) {
347 if (
const auto *PT = dyn_cast<PointerType>(VT);
348 PT && !PT->getPointeeType().isConstQualified() &&
349 !PT->getPointeeType()->isFunctionType())
352 if (
const auto *AT = dyn_cast<ArrayType>(VT)) {
353 assert(AT->getElementType()->isPointerType());
354 if (!AT->getElementType()->getPointeeType().isConstQualified())
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.