Cppcheck
analyzerinfo.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "analyzerinfo.h"
20 
21 #include "errorlogger.h"
22 #include "filesettings.h"
23 #include "path.h"
24 #include "utils.h"
25 
26 #include <cstring>
27 #include <map>
28 
29 #include "xml.h"
30 
32 {
33  close();
34 }
35 
36 static std::string getFilename(const std::string &fullpath)
37 {
38  std::string::size_type pos1 = fullpath.find_last_of("/\\");
39  pos1 = (pos1 == std::string::npos) ? 0U : (pos1 + 1U);
40  std::string::size_type pos2 = fullpath.rfind('.');
41  if (pos2 < pos1)
42  pos2 = std::string::npos;
43  if (pos2 != std::string::npos)
44  pos2 = pos2 - pos1;
45  return fullpath.substr(pos1,pos2);
46 }
47 
48 void AnalyzerInformation::writeFilesTxt(const std::string &buildDir, const std::list<std::string> &sourcefiles, const std::string &userDefines, const std::list<FileSettings> &fileSettings)
49 {
50  std::map<std::string, unsigned int> fileCount;
51 
52  const std::string filesTxt(buildDir + "/files.txt");
53  std::ofstream fout(filesTxt);
54  for (const std::string &f : sourcefiles) {
55  const std::string afile = getFilename(f);
56  fout << afile << ".a" << (++fileCount[afile]) << "::" << Path::simplifyPath(Path::fromNativeSeparators(f)) << '\n';
57  if (!userDefines.empty())
58  fout << afile << ".a" << (++fileCount[afile]) << ":" << userDefines << ":" << Path::simplifyPath(Path::fromNativeSeparators(f)) << '\n';
59  }
60 
61  for (const FileSettings &fs : fileSettings) {
62  const std::string afile = getFilename(fs.filename());
63  fout << afile << ".a" << (++fileCount[afile]) << ":" << fs.cfg << ":" << Path::simplifyPath(Path::fromNativeSeparators(fs.filename())) << std::endl;
64  }
65 }
66 
68 {
69  mAnalyzerInfoFile.clear();
70  if (mOutputStream.is_open()) {
71  mOutputStream << "</analyzerinfo>\n";
72  mOutputStream.close();
73  }
74 }
75 
76 static bool skipAnalysis(const std::string &analyzerInfoFile, std::size_t hash, std::list<ErrorMessage> &errors)
77 {
78  tinyxml2::XMLDocument doc;
79  const tinyxml2::XMLError error = doc.LoadFile(analyzerInfoFile.c_str());
80  if (error != tinyxml2::XML_SUCCESS)
81  return false;
82 
83  const tinyxml2::XMLElement * const rootNode = doc.FirstChildElement();
84  if (rootNode == nullptr)
85  return false;
86 
87  const char *attr = rootNode->Attribute("hash");
88  if (!attr || attr != std::to_string(hash))
89  return false;
90 
91  for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
92  if (std::strcmp(e->Name(), "error") == 0)
93  errors.emplace_back(e);
94  }
95 
96  return true;
97 }
98 
99 std::string AnalyzerInformation::getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg)
100 {
101  std::string line;
102  const std::string end(':' + cfg + ':' + Path::simplifyPath(sourcefile));
103  while (std::getline(filesTxt,line)) {
104  if (line.size() <= end.size() + 2U)
105  continue;
106  if (!endsWith(line, end.c_str(), end.size()))
107  continue;
108  return line.substr(0,line.find(':'));
109  }
110  return "";
111 }
112 
113 std::string AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg)
114 {
115  std::ifstream fin(Path::join(buildDir, "files.txt"));
116  if (fin.is_open()) {
117  const std::string& ret = getAnalyzerInfoFileFromFilesTxt(fin, sourcefile, cfg);
118  if (!ret.empty())
119  return Path::join(buildDir, ret);
120  }
121 
122  const std::string::size_type pos = sourcefile.rfind('/');
123  std::string filename;
124  if (pos == std::string::npos)
125  filename = sourcefile;
126  else
127  filename = sourcefile.substr(pos + 1);
128  return Path::join(buildDir, filename) + ".analyzerinfo";
129 }
130 
131 bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t hash, std::list<ErrorMessage> &errors)
132 {
133  if (buildDir.empty() || sourcefile.empty())
134  return true;
135  close();
136 
138 
139  if (skipAnalysis(mAnalyzerInfoFile, hash, errors))
140  return false;
141 
143  if (mOutputStream.is_open()) {
144  mOutputStream << "<?xml version=\"1.0\"?>\n";
145  mOutputStream << "<analyzerinfo hash=\"" << hash << "\">\n";
146  } else {
147  mAnalyzerInfoFile.clear();
148  }
149 
150  return true;
151 }
152 
154 {
155  if (mOutputStream.is_open())
156  mOutputStream << msg.toXML() << '\n';
157 }
158 
159 void AnalyzerInformation::setFileInfo(const std::string &check, const std::string &fileInfo)
160 {
161  if (mOutputStream.is_open() && !fileInfo.empty())
162  mOutputStream << " <FileInfo check=\"" << check << "\">\n" << fileInfo << " </FileInfo>\n";
163 }
static bool skipAnalysis(const std::string &analyzerInfoFile, std::size_t hash, std::list< ErrorMessage > &errors)
static std::string getFilename(const std::string &fullpath)
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg)
void reportErr(const ErrorMessage &msg)
void setFileInfo(const std::string &check, const std::string &fileInfo)
void close()
Close current TU.analyzerinfo file.
static std::string getAnalyzerInfoFileFromFilesTxt(std::istream &filesTxt, const std::string &sourcefile, const std::string &cfg)
std::string mAnalyzerInfoFile
Definition: analyzerinfo.h:66
static void writeFilesTxt(const std::string &buildDir, const std::list< std::string > &sourcefiles, const std::string &userDefines, const std::list< FileSettings > &fileSettings)
std::ofstream mOutputStream
Definition: analyzerinfo.h:65
bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t hash, std::list< ErrorMessage > &errors)
Wrapper for error messages, provided by reportErr()
Definition: errorlogger.h:48
std::string toXML() const
Format the error message in XML format.
static std::string simplifyPath(std::string originalPath)
Simplify path "foo/bar/.." => "foo".
Definition: path.cpp:83
static std::string join(const std::string &path1, const std::string &path2)
join 2 paths with '/' separators
Definition: path.cpp:339
static std::string fromNativeSeparators(std::string path)
Convert path to use internal path separators.
Definition: path.cpp:75
@ error
Programming error.
static std::string cfg(const std::vector< std::string > &configs, const std::string &userDefines)
File settings.
Definition: filesettings.h:57
bool endsWith(const std::string &str, char c)
Definition: utils.h:110