Skip to content

Commit a46dab4

Browse files
committed
do not throw simplecpp::Output from Preprocessor::preprocess()
1 parent 04882c0 commit a46dab4

File tree

7 files changed

+95
-49
lines changed

7 files changed

+95
-49
lines changed

lib/cppcheck.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,22 +1142,30 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
11421142
try {
11431143
TokenList tokenlist{mSettings, file.lang()};
11441144

1145-
try {
1145+
{
1146+
bool skipCfg = false;
11461147
// Create tokens, skip rest of iteration if failed
11471148
Timer::run("Tokenizer::createTokens", mSettings.showtime, &s_timerResults, [&]() {
1148-
simplecpp::TokenList tokensP = preprocessor.preprocess(currentConfig, files, true);
1149-
tokenlist.createTokens(std::move(tokensP));
1149+
simplecpp::OutputList outputList_cfg;
1150+
simplecpp::TokenList tokensP = preprocessor.preprocess(currentConfig, files, outputList_cfg);
1151+
const simplecpp::Output* o = preprocessor.handleErrors(outputList_cfg);
1152+
if (!o) {
1153+
tokenlist.createTokens(std::move(tokensP));
1154+
}
1155+
else {
1156+
// #error etc during preprocessing
1157+
configurationError.push_back((currentConfig.empty() ? "\'\'" : currentConfig) + " : [" + o->location.file() + ':' + std::to_string(o->location.line) + "] " + o->msg);
1158+
--checkCount; // don't count invalid configurations
1159+
1160+
if (!hasValidConfig && currCfg == *configurations.rbegin()) {
1161+
// If there is no valid configuration then report error..
1162+
preprocessor.error(o->location.file(), o->location.line, o->location.col, o->msg, o->type);
1163+
}
1164+
skipCfg = true;
1165+
}
11501166
});
1151-
} catch (const simplecpp::Output &o) {
1152-
// #error etc during preprocessing
1153-
configurationError.push_back((currentConfig.empty() ? "\'\'" : currentConfig) + " : [" + o.location.file() + ':' + std::to_string(o.location.line) + "] " + o.msg);
1154-
--checkCount; // don't count invalid configurations
1155-
1156-
if (!hasValidConfig && currCfg == *configurations.rbegin()) {
1157-
// If there is no valid configuration then report error..
1158-
preprocessor.error(o.location.file(), o.location.line, o.location.col, o.msg, o.type);
1159-
}
1160-
continue;
1167+
if (skipCfg)
1168+
continue;
11611169
}
11621170
hasValidConfig = true;
11631171

lib/preprocessor.cpp

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -761,19 +761,10 @@ bool Preprocessor::hasErrors(const simplecpp::Output &output)
761761
return false;
762762
}
763763

764-
bool Preprocessor::handleErrors(const simplecpp::OutputList& outputList, bool throwError)
764+
const simplecpp::Output* Preprocessor::handleErrors(const simplecpp::OutputList& outputList)
765765
{
766766
const bool showerror = (!mSettings.userDefines.empty() && !mSettings.force);
767-
const bool hasError = reportOutput(outputList, showerror);
768-
if (throwError) {
769-
const auto it = std::find_if(outputList.cbegin(), outputList.cend(), [](const simplecpp::Output &output){
770-
return hasErrors(output);
771-
});
772-
if (it != outputList.cend()) {
773-
throw *it;
774-
}
775-
}
776-
return hasError;
767+
return reportOutput(outputList, showerror);
777768
}
778769

779770
bool Preprocessor::loadFiles(std::vector<std::string> &files)
@@ -782,7 +773,7 @@ bool Preprocessor::loadFiles(std::vector<std::string> &files)
782773

783774
simplecpp::OutputList outputList;
784775
mFileCache = simplecpp::load(mTokens, files, dui, &outputList);
785-
return !handleErrors(outputList, false);
776+
return !handleErrors(outputList);
786777
}
787778

788779
void Preprocessor::removeComments()
@@ -813,28 +804,27 @@ void Preprocessor::setPlatformInfo()
813804
mTokens.sizeOfType["long double *"] = mSettings.platform.sizeof_pointer;
814805
}
815806

816-
simplecpp::TokenList Preprocessor::preprocess(const std::string &cfg, std::vector<std::string> &files, bool throwError)
807+
simplecpp::TokenList Preprocessor::preprocess(const std::string &cfg, std::vector<std::string> &files, simplecpp::OutputList& outputList)
817808
{
818809
const simplecpp::DUI dui = createDUI(mSettings, cfg, mLang);
819810

820-
simplecpp::OutputList outputList;
821811
std::list<simplecpp::MacroUsage> macroUsage;
822812
std::list<simplecpp::IfCond> ifCond;
823813
simplecpp::TokenList tokens2(files);
824814
simplecpp::preprocess(tokens2, mTokens, files, mFileCache, dui, &outputList, &macroUsage, &ifCond);
825815
mMacroUsage = std::move(macroUsage);
826816
mIfCond = std::move(ifCond);
827817

828-
(void)handleErrors(outputList, throwError);
829-
830818
tokens2.removeComments();
831819

832820
return tokens2;
833821
}
834822

835823
std::string Preprocessor::getcode(const std::string &cfg, std::vector<std::string> &files, const bool writeLocations)
836824
{
837-
simplecpp::TokenList tokens2 = preprocess(cfg, files, false);
825+
simplecpp::OutputList outputList;
826+
simplecpp::TokenList tokens2 = preprocess(cfg, files, outputList);
827+
handleErrors(outputList);
838828
unsigned int prevfile = 0;
839829
unsigned int line = 1;
840830
std::ostringstream ret;
@@ -859,14 +849,14 @@ std::string Preprocessor::getcode(const std::string &cfg, std::vector<std::strin
859849
return ret.str();
860850
}
861851

862-
bool Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool showerror)
852+
const simplecpp::Output* Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool showerror)
863853
{
864-
bool hasError = false;
854+
const simplecpp::Output* out_ret = nullptr;
865855

866856
for (const simplecpp::Output &out : outputList) {
867857
switch (out.type) {
868858
case simplecpp::Output::ERROR:
869-
hasError = true;
859+
out_ret = &out;
870860
if (!startsWith(out.msg,"#error") || showerror)
871861
error(out.location.file(), out.location.line, out.location.col, out.msg, out.type);
872862
break;
@@ -884,19 +874,19 @@ bool Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh
884874
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
885875
case simplecpp::Output::SYNTAX_ERROR:
886876
case simplecpp::Output::UNHANDLED_CHAR_ERROR:
887-
hasError = true;
877+
out_ret = &out;
888878
error(out.location.file(), out.location.line, out.location.col, out.msg, out.type);
889879
break;
890880
case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND:
891881
case simplecpp::Output::FILE_NOT_FOUND:
892882
case simplecpp::Output::DUI_ERROR:
893-
hasError = true;
883+
out_ret = &out;
894884
error("", 0, 0, out.msg, out.type);
895885
break;
896886
}
897887
}
898888

899-
return hasError;
889+
return out_ret;
900890
}
901891

902892
static std::string simplecppErrToId(simplecpp::Output::Type type)

lib/preprocessor.h

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,7 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {
118118

119119
void setPlatformInfo();
120120

121-
/**
122-
* @throws simplecpp::Output thrown in case of preprocessing error if throwError is true
123-
*/
124-
simplecpp::TokenList preprocess(const std::string &cfg, std::vector<std::string> &files, bool throwError = false);
121+
simplecpp::TokenList preprocess(const std::string &cfg, std::vector<std::string> &files, simplecpp::OutputList& outputList);
125122

126123
std::string getcode(const std::string &cfg, std::vector<std::string> &files, bool writeLocations);
127124

@@ -142,18 +139,15 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {
142139
*/
143140
void dump(std::ostream &out) const;
144141

145-
bool reportOutput(const simplecpp::OutputList &outputList, bool showerror);
142+
const simplecpp::Output* reportOutput(const simplecpp::OutputList &outputList, bool showerror);
146143

147144
void error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, simplecpp::Output::Type type);
148145

146+
const simplecpp::Output* handleErrors(const simplecpp::OutputList &outputList);
147+
149148
private:
150149
static bool hasErrors(const simplecpp::Output &output);
151150

152-
/**
153-
* @throws simplecpp::Output thrown in case of preprocessing error if throwError is true
154-
*/
155-
bool handleErrors(const simplecpp::OutputList &outputList, bool throwError);
156-
157151
static void simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList);
158152

159153
/**

test/cli/other_test.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3986,3 +3986,51 @@ def test_max_configs(tmp_path, max_configs, number_of_configs, check_config, exp
39863986
'{}:0:0: information: Too many #ifdef configurations - cppcheck only checks {} of {} configurations. Use --force to check all configurations. [toomanyconfigs]'
39873987
.format(test_file, max_configs, number_of_configs)
39883988
]
3989+
3990+
3991+
def test_no_valid_configuration(tmp_path):
3992+
test_file = tmp_path / 'test.c'
3993+
with open(test_file, "w") as f:
3994+
f.write(
3995+
"""#include ""
3996+
#ifdef DEF_1
3997+
#include ""
3998+
#endif
3999+
""")
4000+
4001+
args = [
4002+
'--template=simple',
4003+
'--emit-duplicates',
4004+
'--enable=information',
4005+
'--suppress=checkersReport',
4006+
str(test_file)
4007+
]
4008+
4009+
exitcode, stdout, stderr = cppcheck(args)
4010+
assert exitcode == 0, stdout
4011+
assert stdout.splitlines() == [
4012+
'Checking {} ...'.format(test_file)
4013+
]
4014+
# TODO: this lacks context about the configuration which encounters these errors
4015+
# TODO: add message when a configuration is dropped?
4016+
assert stderr.splitlines() == [
4017+
# TODO: should only report the error once
4018+
'{}:1:2: error: No header in #include [syntaxError]'.format(test_file),
4019+
'{}:1:2: error: No header in #include [syntaxError]'.format(test_file),
4020+
'{}:1:2: error: No header in #include [syntaxError]'.format(test_file),
4021+
'{}:0:0: information: This file is not analyzed. Cppcheck failed to extract a valid configuration. Use -v for more details. [noValidConfiguration]'.format(test_file)
4022+
]
4023+
4024+
args += ['--check-config']
4025+
4026+
exitcode, stdout, stderr = cppcheck(args)
4027+
assert exitcode == 0, stdout
4028+
assert stdout.splitlines() == [
4029+
'Checking {} ...'.format(test_file)
4030+
]
4031+
# TODO: this lacks context about the configuration which encounters these errors
4032+
# TODO: add message when a configuration is dropped
4033+
assert stderr.splitlines() == [
4034+
'{}:1:2: error: No header in #include [syntaxError]'.format(test_file),
4035+
'{}:1:2: error: No header in #include [syntaxError]'.format(test_file)
4036+
]

test/helpers.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ void SimpleTokenizer2::preprocess(const char* code, std::size_t size, std::vecto
116116
simplecpp::TokenList tokens1(code, size, files, file0);
117117

118118
Preprocessor preprocessor(tokens1, tokenizer.getSettings(), errorlogger, Path::identify(tokens1.getFiles()[0], false));
119-
simplecpp::TokenList tokens2 = preprocessor.preprocess("", files, true);
119+
simplecpp::OutputList outputList;
120+
simplecpp::TokenList tokens2 = preprocessor.preprocess("", files, outputList);
121+
(void)preprocessor.reportOutput(outputList, true);
120122

121123
// Tokenizer..
122124
tokenizer.list.createTokens(std::move(tokens2));

test/testpreprocessor.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ class TestPreprocessor : public TestFixture {
5555
std::vector<std::string> files;
5656
simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", &outputList);
5757
Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false));
58-
simplecpp::TokenList tokens2 = p.preprocess("", files, true);
5958
(void)p.reportOutput(outputList, true);
59+
simplecpp::OutputList outputList_pp;
60+
simplecpp::TokenList tokens2 = p.preprocess("", files, outputList_pp);
61+
(void)p.reportOutput(outputList_pp, true);
6062
return tokens2.stringify();
6163
}
6264

test/testtokenlist.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@ class TestTokenList : public TestFixture {
158158
std::vector<std::string> files;
159159
simplecpp::TokenList tokens1(code, files, "poll.h", nullptr);
160160
Preprocessor preprocessor(tokens1, settingsDefault, *this, Path::identify(tokens1.getFiles()[0], false));
161-
simplecpp::TokenList tokensP = preprocessor.preprocess("", files, true);
161+
simplecpp::OutputList outputList_pp;
162+
simplecpp::TokenList tokensP = preprocessor.preprocess("", files, outputList_pp);
163+
ASSERT(!preprocessor.reportOutput(outputList_pp, true));
162164
TokenList tokenlist(settingsDefault, Standards::Language::C); // headers are treated as C files
163165
tokenlist.createTokens(std::move(tokensP)); // do not assert
164166
}

0 commit comments

Comments
 (0)