Skip to content

Commit 0ce48a0

Browse files
author
Your Name
committed
Refactor the functions
1 parent 93e947d commit 0ce48a0

2 files changed

Lines changed: 93 additions & 85 deletions

File tree

lib/templatesimplifier.cpp

Lines changed: 85 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -824,17 +824,28 @@ namespace {
824824
isLong == other.isLong;
825825
}
826826
};
827+
828+
// A parsed function template declaration that type deduction supports. Invalid
829+
// (typeParameters is empty) when the declaration is not supported.
830+
struct DeductionCandidate {
831+
std::vector<const Token*> typeParameters;
832+
std::vector<ParameterShape> parameterShapes;
833+
std::string signature;
834+
};
827835
}
828836

829-
static bool parseParameterShape(const Token* start, const std::vector<const Token*>& typeParameters, ParameterShape& shape)
837+
// Parse a function parameter of a template declaration. The returned shape has no
838+
// typeTok when the parameter does not have a supported form.
839+
static ParameterShape parseParameterShape(const Token* start, const std::vector<const Token*>& typeParameters)
830840
{
841+
ParameterShape shape;
831842
const Token* tok = start;
832843
if (Token::simpleMatch(tok, "const")) {
833844
shape.isConst = true;
834845
tok = tok->next();
835846
}
836847
if (!Token::Match(tok, "%type%") || Token::Match(tok, "const|struct|class|union|enum"))
837-
return false;
848+
return ParameterShape();
838849
shape.typeTok = tok;
839850
tok = tok->next();
840851
if (Token::simpleMatch(tok, "*")) {
@@ -847,32 +858,33 @@ static bool parseParameterShape(const Token* start, const std::vector<const Toke
847858
if (Token::Match(tok, "%name% ,|)"))
848859
tok = tok->next();
849860
if (!Token::Match(tok, ",|)"))
850-
return false;
861+
return ParameterShape();
851862
const auto it = std::find_if(typeParameters.cbegin(), typeParameters.cend(), [&](const Token* typeParameter) {
852863
return typeParameter->str() == shape.typeTok->str();
853864
});
854865
if (it != typeParameters.cend())
855866
shape.templateParameterIndex = static_cast<int>(it - typeParameters.cbegin());
856-
return true;
867+
return shape;
857868
}
858869

859870
// Convert the ValueType of an argument expression to the type that the parameter shape
860-
// deduces for its template parameter. Returns false when the type is not supported.
861-
static bool valueTypeToDeducedType(const ValueType* vt, const ParameterShape& shape, DeducedType& deduced)
871+
// deduces for its template parameter. The returned type has an empty typeStr when the
872+
// type is not supported.
873+
static DeducedType valueTypeToDeducedType(const ValueType* vt, const ParameterShape& shape)
862874
{
863875
if (!vt)
864-
return false;
876+
return DeducedType();
865877
if (vt->bits > 0 || vt->volatileness != 0)
866-
return false;
878+
return DeducedType();
867879
if (vt->smartPointer || vt->smartPointerType || vt->smartPointerTypeToken || vt->container || vt->containerTypeToken)
868-
return false;
880+
return DeducedType();
869881

870882
int pointer = vt->pointer;
871883
unsigned int constness = vt->constness;
872884
if (shape.isPointer) {
873885
// "T *": the argument must be a pointer and T is the pointee type
874886
if (pointer < 1)
875-
return false;
887+
return DeducedType();
876888
constness &= ~(1U << pointer);
877889
--pointer;
878890
} else if (!shape.isReference || shape.isConst) {
@@ -882,9 +894,10 @@ static bool valueTypeToDeducedType(const ValueType* vt, const ParameterShape& sh
882894
// else "T &": the constness is part of the deduced type
883895

884896
if (pointer > 2)
885-
return false;
897+
return DeducedType();
886898
if (constness >= (1U << (pointer + 1)))
887-
return false;
899+
return DeducedType();
900+
DeducedType deduced;
888901
deduced.pointer = pointer;
889902
deduced.constness = constness;
890903

@@ -929,22 +942,22 @@ static bool valueTypeToDeducedType(const ValueType* vt, const ParameterShape& sh
929942
case ValueType::RECORD: {
930943
const Scope* typeScope = vt->typeScope;
931944
if (!typeScope || typeScope->className.empty() || !typeScope->isClassOrStructOrUnion())
932-
return false;
945+
return DeducedType();
933946
deduced.typeStr = typeScope->className;
934947
for (const Scope* nested = typeScope->nestedIn; nested && nested->type != ScopeType::eGlobal; nested = nested->nestedIn) {
935948
if (nested->type != ScopeType::eNamespace && !nested->isClassOrStructOrUnion())
936-
return false; // local types etc. cannot be named - bail out
949+
return DeducedType(); // local types etc. cannot be named - bail out
937950
if (nested->className.empty())
938-
return false;
951+
return DeducedType();
939952
deduced.qualification.insert(deduced.qualification.cbegin(), nested->className);
940953
}
941954
break;
942955
}
943956
default:
944-
return false;
957+
return DeducedType();
945958
}
946959

947-
return true;
960+
return deduced;
948961
}
949962

950963
// Is there a non template function with the given name in the scope? Overload
@@ -990,14 +1003,14 @@ static void insertDeducedType(Token* tok, const DeducedType& deduced)
9901003
tok->insertToken("const");
9911004
}
9921005

993-
void TemplateSimplifier::deduceFunctionTemplateArguments(Token* tok,
994-
std::string& qualification,
995-
const std::string& scopeName,
996-
const std::multimap<std::string, const TokenAndName*>& functionNameMap)
1006+
std::string TemplateSimplifier::deduceFunctionTemplateArguments(Token* tok,
1007+
std::string qualification,
1008+
const std::string& scopeName,
1009+
const std::multimap<std::string, const TokenAndName*>& functionNameMap)
9971010
{
9981011
const auto range = functionNameMap.equal_range(tok->str());
9991012
if (range.first == range.second)
1000-
return;
1013+
return qualification;
10011014

10021015
std::string fullName;
10031016
if (!qualification.empty())
@@ -1096,85 +1109,82 @@ void TemplateSimplifier::deduceFunctionTemplateArguments(Token* tok,
10961109
break;
10971110
}
10981111
tok->insertToken("<");
1099-
return;
1112+
return qualification;
11001113
}
11011114
}
11021115
}
11031116

11041117
// the remaining deduction needs the types of the argument expressions
11051118
if (instantiationArgs.empty())
1106-
return;
1119+
return qualification;
11071120

11081121
// a call through a variable (function object, function pointer) is not a template instantiation
11091122
if (tok->varId() != 0)
1110-
return;
1123+
return qualification;
11111124
// a call that the symbol database resolved to a real (non template) function must not
11121125
// be hijacked - overload resolution against non templates is not implemented here
11131126
if (tok->function() && !tok->function()->templateDef)
1114-
return;
1127+
return qualification;
11151128

11161129
// Parse a candidate declaration: all parameters must have a supported form and
11171130
// every template parameter must be deducible from the function parameters. The
11181131
// signature identifies the parameter list, so a forward declaration and the
11191132
// definition of the same template can be recognized.
1120-
auto parseDeductionCandidate = [&](const TokenAndName& candidate,
1121-
std::vector<const Token*>& typeParameters,
1122-
std::vector<ParameterShape>& parameterShapes,
1123-
std::string& signature) -> bool {
1133+
auto parseDeductionCandidate = [&](const TokenAndName& candidate) -> DeductionCandidate {
11241134
if (candidate.isVariadic())
1125-
return false;
1135+
return DeductionCandidate();
11261136

1127-
getTemplateParametersInDeclaration(candidate.token()->tokAt(2), typeParameters);
1128-
if (typeParameters.empty() || !areAllParamsTypes(typeParameters))
1129-
return false;
1137+
DeductionCandidate parsed;
1138+
getTemplateParametersInDeclaration(candidate.token()->tokAt(2), parsed.typeParameters);
1139+
if (parsed.typeParameters.empty() || !areAllParamsTypes(parsed.typeParameters))
1140+
return DeductionCandidate();
11301141

11311142
std::vector<const Token*> declarationParams;
11321143
getFunctionArguments(candidate.nameToken(), declarationParams);
11331144
if (declarationParams.size() != instantiationArgs.size())
1134-
return false;
1145+
return DeductionCandidate();
11351146

1136-
std::vector<bool> deducible(typeParameters.size(), false);
1137-
signature = candidate.fullName();
1147+
std::vector<bool> deducible(parsed.typeParameters.size(), false);
1148+
parsed.signature = candidate.fullName();
11381149
for (const Token* param : declarationParams) {
1139-
ParameterShape shape;
1140-
if (!parseParameterShape(param, typeParameters, shape))
1141-
return false;
1150+
const ParameterShape shape = parseParameterShape(param, parsed.typeParameters);
1151+
if (!shape.typeTok)
1152+
return DeductionCandidate();
11421153
if (shape.templateParameterIndex >= 0)
11431154
deducible[shape.templateParameterIndex] = true;
1144-
parameterShapes.push_back(shape);
1145-
signature += (shape.isConst ? " const" : "");
1155+
parsed.parameterShapes.push_back(shape);
1156+
parsed.signature += (shape.isConst ? " const" : "");
11461157
// template parameters are compared by position - their names may differ
11471158
// between a forward declaration and the definition
11481159
if (shape.templateParameterIndex >= 0)
1149-
signature += " $" + std::to_string(shape.templateParameterIndex);
1160+
parsed.signature += " $" + std::to_string(shape.templateParameterIndex);
11501161
else
1151-
signature += " " + shape.typeTok->str();
1152-
signature += (shape.isPointer ? " *" : shape.isReference ? " &" : "");
1153-
signature += ",";
1162+
parsed.signature += " " + shape.typeTok->str();
1163+
parsed.signature += (shape.isPointer ? " *" : shape.isReference ? " &" : "");
1164+
parsed.signature += ",";
11541165
}
1155-
return std::all_of(deducible.cbegin(), deducible.cend(), [](bool b) {
1166+
if (!std::all_of(deducible.cbegin(), deducible.cend(), [](bool b) {
11561167
return b;
1157-
});
1168+
}))
1169+
return DeductionCandidate();
1170+
return parsed;
11581171
};
11591172

11601173
if (!mUseTypeInformation) {
11611174
// Can the deduction succeed later, when type information is available? Scope
11621175
// matching is not possible yet - the declaration may be in a base class - so
11631176
// consider all declarations with this name.
11641177
for (auto pos = range.first; pos != range.second; ++pos) {
1165-
std::vector<const Token*> typeParameters;
1166-
std::vector<ParameterShape> parameterShapes;
1167-
std::string signature;
1168-
if (parseDeductionCandidate(*pos->second, typeParameters, parameterShapes, signature)) {
1178+
if (!parseDeductionCandidate(*pos->second).typeParameters.empty()) {
11691179
mPendingTypeDeductions = true;
1170-
return;
1180+
return qualification;
11711181
}
11721182
}
1173-
return;
1183+
return qualification;
11741184
}
11751185

11761186
if (!tok->scope())
1177-
return;
1187+
return qualification;
11781188

11791189
// The scopes where the call name is looked up, in lookup order: the innermost scope
11801190
// with matching declarations wins. At class scopes the transitive base classes are
@@ -1241,7 +1251,7 @@ void TemplateSimplifier::deduceFunctionTemplateArguments(Token* tok,
12411251
for (const LookupLevel& level : levels) {
12421252
// a non template function with the same name might be a better overload match
12431253
if (level.scope && scopeHasNonTemplateFunction(level.scope, tok->str()))
1244-
return;
1254+
return qualification;
12451255
const std::string lookupName = level.scopeName.empty() ? tok->str() : (level.scopeName + " :: " + tok->str());
12461256
for (auto pos = range.first; pos != range.second; ++pos) {
12471257
if (pos->second->fullName() == lookupName)
@@ -1256,53 +1266,47 @@ void TemplateSimplifier::deduceFunctionTemplateArguments(Token* tok,
12561266

12571267
// parse the candidate declarations
12581268
const TokenAndName* declaration = nullptr;
1259-
std::vector<const Token*> typeParameters;
1260-
std::vector<ParameterShape> parameterShapes;
1261-
std::string declarationSignature;
1269+
DeductionCandidate parsedDeclaration;
12621270
for (const TokenAndName* candidate : candidates) {
1263-
std::vector<const Token*> candidateTypeParameters;
1264-
std::vector<ParameterShape> candidateShapes;
1265-
std::string signature;
1266-
if (!parseDeductionCandidate(*candidate, candidateTypeParameters, candidateShapes, signature))
1271+
DeductionCandidate parsed = parseDeductionCandidate(*candidate);
1272+
if (parsed.typeParameters.empty())
12671273
continue;
12681274

12691275
if (declaration) {
12701276
// multiple overloads could match: overload resolution is not implemented => bail out
1271-
if (signature != declarationSignature)
1272-
return;
1277+
if (parsed.signature != parsedDeclaration.signature)
1278+
return qualification;
12731279
continue; // forward declaration and definition of the same template
12741280
}
12751281
declaration = candidate;
1276-
typeParameters = std::move(candidateTypeParameters);
1277-
parameterShapes = std::move(candidateShapes);
1278-
declarationSignature = std::move(signature);
1282+
parsedDeclaration = std::move(parsed);
12791283
}
12801284
if (!declaration)
1281-
return;
1285+
return qualification;
12821286

12831287
// deduce the template parameters from the ValueTypes of the argument expressions
12841288
const std::vector<const Token*> argRoots = getArguments(tok);
12851289
if (argRoots.size() != instantiationArgs.size())
1286-
return;
1287-
std::vector<DeducedType> deducedTypes(typeParameters.size());
1288-
std::vector<bool> deducedSet(typeParameters.size(), false);
1289-
for (std::size_t i = 0; i < parameterShapes.size(); ++i) {
1290-
const ParameterShape& shape = parameterShapes[i];
1290+
return qualification;
1291+
std::vector<DeducedType> deducedTypes(parsedDeclaration.typeParameters.size());
1292+
std::vector<bool> deducedSet(parsedDeclaration.typeParameters.size(), false);
1293+
for (std::size_t i = 0; i < parsedDeclaration.parameterShapes.size(); ++i) {
1294+
const ParameterShape& shape = parsedDeclaration.parameterShapes[i];
12911295
if (shape.templateParameterIndex < 0)
12921296
continue;
12931297
const ValueType* vt = argRoots[i]->valueType();
12941298
if (!vt) {
12951299
// type information is not available (yet) for this argument
12961300
mPendingTypeDeductions = true;
1297-
return;
1301+
return qualification;
12981302
}
1299-
DeducedType deduced;
1300-
if (!valueTypeToDeducedType(vt, shape, deduced))
1301-
return;
1303+
DeducedType deduced = valueTypeToDeducedType(vt, shape);
1304+
if (deduced.typeStr.empty())
1305+
return qualification;
13021306
if (deducedSet[shape.templateParameterIndex]) {
13031307
// inconsistent deduction => don't deduce
13041308
if (!(deducedTypes[shape.templateParameterIndex] == deduced))
1305-
return;
1309+
return qualification;
13061310
} else {
13071311
deducedTypes[shape.templateParameterIndex] = std::move(deduced);
13081312
deducedSet[shape.templateParameterIndex] = true;
@@ -1338,6 +1342,7 @@ void TemplateSimplifier::deduceFunctionTemplateArguments(Token* tok,
13381342
rememberDirtyCallSite(tok);
13391343
mTypeDeductionsMade = true;
13401344
mChanged = true;
1345+
return qualification;
13411346
}
13421347

13431348
void TemplateSimplifier::getTemplateInstantiations()
@@ -1417,7 +1422,7 @@ void TemplateSimplifier::getTemplateInstantiations()
14171422

14181423
// look for function instantiation with type deduction
14191424
if (tok->strAt(1) == "(")
1420-
deduceFunctionTemplateArguments(tok, qualification, scopeName, functionNameMap);
1425+
qualification = deduceFunctionTemplateArguments(tok, qualification, scopeName, functionNameMap);
14211426

14221427
if (!Token::Match(tok, "%name% <") ||
14231428
Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast"))

lib/templatesimplifier.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,14 @@ class CPPCHECKLIB TemplateSimplifier {
425425
* @param qualification qualification of the call ("A :: B" for "A :: B :: f ( 1 )")
426426
* @param scopeName name of the scope the call is in
427427
* @param functionNameMap map with all function template declarations
428-
*/
429-
void deduceFunctionTemplateArguments(Token* tok,
430-
std::string& qualification,
431-
const std::string& scopeName,
432-
const std::multimap<std::string, const TokenAndName*>& functionNameMap);
428+
* @return the qualification of the call: the given qualification, or the scope of
429+
* the deduced declaration when it is in a base class and explicit qualification
430+
* was inserted at the call site
431+
*/
432+
std::string deduceFunctionTemplateArguments(Token* tok,
433+
std::string qualification,
434+
const std::string& scopeName,
435+
const std::multimap<std::string, const TokenAndName*>& functionNameMap);
433436

434437
/**
435438
* Remember that the given instantiated function template declaration should not be

0 commit comments

Comments
 (0)