41 AnalyzePointers(Options.get(
"AnalyzePointers", true)),
42 AnalyzeReferences(Options.get(
"AnalyzeReferences", true)),
43 AnalyzeValues(Options.get(
"AnalyzeValues", true)),
45 WarnPointersAsPointers(Options.get(
"WarnPointersAsPointers", true)),
46 WarnPointersAsValues(Options.get(
"WarnPointersAsValues", false)),
48 TransformPointersAsPointers(
49 Options.get(
"TransformPointersAsPointers", true)),
50 TransformPointersAsValues(
51 Options.get(
"TransformPointersAsValues", false)),
52 TransformReferences(Options.get(
"TransformReferences", true)),
53 TransformValues(Options.get(
"TransformValues", true)),
56 utils::options::parseStringList(Options.get(
"AllowedTypes",
""))) {
57 if (AnalyzeValues ==
false && AnalyzeReferences ==
false &&
58 AnalyzePointers ==
false)
59 this->configurationDiag(
60 "The check 'misc-const-correctness' will not "
61 "perform any analysis because 'AnalyzeValues', "
62 "'AnalyzeReferences' and 'AnalyzePointers' are false.");
84 const auto ConstType =
85 hasType(qualType(isConstQualified(),
87 unless(pointerType())));
89 const auto ConstReference = hasType(references(isConstQualified()));
90 const auto RValueReference = hasType(
91 referenceType(anyOf(rValueReferenceType(), unless(isSpelledAsLValue()))));
93 const auto TemplateType = anyOf(
94 hasType(hasCanonicalType(templateTypeParmType())),
95 hasType(substTemplateTypeParmType()), hasType(isDependentType()),
98 hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))),
99 hasType(referenceType(pointee(substTemplateTypeParmType()))));
101 auto AllowedTypeDecl = namedDecl(
104 const auto AllowedType = hasType(qualType(
105 anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl),
106 pointerType(pointee(hasDeclaration(AllowedTypeDecl))))));
108 const auto AutoTemplateType = varDecl(
109 anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))),
110 hasType(pointerType(pointee(autoType())))));
112 const auto FunctionPointerRef =
113 hasType(hasCanonicalType(referenceType(pointee(functionType()))));
117 const auto LocalValDecl = varDecl(
118 isLocal(), hasInitializer(anything()),
119 unless(anyOf(ConstType, ConstReference, TemplateType,
120 hasInitializer(isInstantiationDependent()), AutoTemplateType,
121 RValueReference, FunctionPointerRef,
122 hasType(cxxRecordDecl(isLambda())), isImplicit(),
127 const auto FunctionScope =
129 hasBody(stmt(forEachDescendant(
130 declStmt(containsAnyDeclaration(
131 LocalValDecl.bind(
"local-value")),
132 unless(has(decompositionDecl())))
135 .bind(
"function-decl");
137 Finder->addMatcher(FunctionScope,
this);
144 const auto *LocalScope = Result.Nodes.getNodeAs<Stmt>(
"scope");
145 const auto *Variable = Result.Nodes.getNodeAs<VarDecl>(
"local-value");
146 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(
"function-decl");
147 const auto *VarDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
"decl-stmt");
151 const bool CanBeFixIt = VarDeclStmt !=
nullptr && VarDeclStmt->isSingleDecl();
158 bool IsNormalVariableInTemplate = Function->isTemplateInstantiation();
159 if (IsNormalVariableInTemplate &&
160 TemplateDiagnosticsCache.contains(Variable->getBeginLoc()))
164 const QualType VT = Variable->getType();
165 if (VT->isReferenceType()) {
167 }
else if (VT->isPointerType()) {
169 }
else if (
const auto *ArrayT = dyn_cast<ArrayType>(VT)) {
170 if (ArrayT->getElementType()->isPointerType())
174 auto CheckValue = [&]() {
176 registerScope(LocalScope, Result.Context);
179 if (ScopesCache[LocalScope]->isMutated(Variable))
182 auto Diag = diag(Variable->getBeginLoc(),
183 "variable %0 of type %1 can be declared 'const'")
185 if (IsNormalVariableInTemplate)
186 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
191 Diag << addQualifierToVarDecl(*Variable, *Result.Context,
192 Qualifiers::Const, QualifierTarget::Value,
193 QualifierPolicy::Right);
200 Diag << addQualifierToVarDecl(*Variable, *Result.Context,
201 Qualifiers::Const, QualifierTarget::Value,
202 QualifierPolicy::Right);
207 Diag << addQualifierToVarDecl(*Variable, *Result.Context,
208 Qualifiers::Const, QualifierTarget::Value,
209 QualifierPolicy::Right);
214 auto CheckPointee = [&]() {
216 registerScope(LocalScope, Result.Context);
217 if (ScopesCache[LocalScope]->isPointeeMutated(Variable))
220 diag(Variable->getBeginLoc(),
221 "pointee of variable %0 of type %1 can be declared 'const'")
223 if (IsNormalVariableInTemplate)
224 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
228 if (TransformPointersAsPointers) {
229 Diag << addQualifierToVarDecl(*Variable, *Result.Context,
230 Qualifiers::Const, QualifierTarget::Pointee,
231 QualifierPolicy::Right);
242 if (VT->getPointeeType()->isPointerType() && !WarnPointersAsValues)
248 if (WarnPointersAsValues && !VT.isConstQualified())
250 if (WarnPointersAsPointers) {
251 if (
const auto *PT = dyn_cast<PointerType>(VT)) {
252 if (!PT->getPointeeType().isConstQualified())
255 if (
const auto *AT = dyn_cast<ArrayType>(VT)) {
256 if (!AT->getElementType().isConstQualified()) {
257 assert(AT->getElementType()->isPointerType());
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.