1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of Qt Creator. 7 ** 8 ** Commercial License Usage 9 ** Licensees holding valid commercial Qt licenses may use this file in 10 ** accordance with the commercial license agreement provided with the 11 ** Software or, alternatively, in accordance with the terms contained in 12 ** a written agreement between you and The Qt Company. For licensing terms 13 ** and conditions see https://www.qt.io/terms-conditions. For further 14 ** information use the contact form at https://www.qt.io/contact-us. 15 ** 16 ** GNU General Public License Usage 17 ** Alternatively, this file may be used under the terms of the GNU 18 ** General Public License version 3 as published by the Free Software 19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 ** included in the packaging of this file. Please review the following 21 ** information to ensure the GNU General Public License requirements will 22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 ** 24 ****************************************************************************/ 25 26 #pragma once 27 28 #include "Macro.h" 29 30 #include <cplusplus/CPlusPlusForwardDeclarations.h> 31 #include <cplusplus/PreprocessorClient.h> 32 #include <cplusplus/DependencyTable.h> 33 34 #include <utils/fileutils.h> 35 36 #include <QSharedPointer> 37 #include <QDateTime> 38 #include <QHash> 39 #include <QFileInfo> 40 #include <QAtomicInt> 41 42 QT_BEGIN_NAMESPACE 43 class QFutureInterfaceBase; 44 QT_END_NAMESPACE 45 46 namespace CPlusPlus { 47 48 class Macro; 49 class MacroArgumentReference; 50 class LookupContext; 51 52 class CPLUSPLUS_EXPORT Document 53 { 54 Document(const Document &other); 55 void operator =(const Document &other); 56 57 Document(const QString &fileName); 58 59 public: 60 typedef QSharedPointer<Document> Ptr; 61 62 public: 63 ~Document(); 64 65 unsigned revision() const; 66 void setRevision(unsigned revision); 67 68 unsigned editorRevision() const; 69 void setEditorRevision(unsigned editorRevision); 70 71 QDateTime lastModified() const; 72 void setLastModified(const QDateTime &lastModified); 73 74 QString fileName() const; 75 76 void appendMacro(const Macro ¯o); 77 void addMacroUse(const Macro ¯o, 78 int bytesOffset, int bytesLength, 79 int utf16charsOffset, int utf16charLength, 80 int beginLine, const QVector<MacroArgumentReference> &range); 81 void addUndefinedMacroUse(const QByteArray &name, 82 int bytesOffset, int utf16charsOffset); 83 84 Control *control() const; 85 Control *swapControl(Control *newControl); 86 TranslationUnit *translationUnit() const; 87 88 bool skipFunctionBody() const; 89 void setSkipFunctionBody(bool skipFunctionBody); 90 91 int globalSymbolCount() const; 92 Symbol *globalSymbolAt(int index) const; 93 94 Namespace *globalNamespace() const; 95 void setGlobalNamespace(Namespace *globalNamespace); // ### internal 96 definedMacros()97 QList<Macro> definedMacros() const 98 { return _definedMacros; } 99 100 QString functionAt(int line, int column, int *lineOpeningDeclaratorParenthesis = nullptr, 101 int *lineClosingBrace = nullptr) const; 102 Symbol *lastVisibleSymbolAt(int line, int column = 0) const; 103 Scope *scopeAt(int line, int column = 0); 104 105 QByteArray utf8Source() const; 106 void setUtf8Source(const QByteArray &utf8Source); 107 fingerprint()108 QByteArray fingerprint() const { return m_fingerprint; } setFingerprint(const QByteArray & fingerprint)109 void setFingerprint(const QByteArray &fingerprint) 110 { m_fingerprint = fingerprint; } 111 112 LanguageFeatures languageFeatures() const; 113 void setLanguageFeatures(LanguageFeatures features); 114 115 void startSkippingBlocks(int utf16charsOffset); 116 void stopSkippingBlocks(int utf16charsOffset); 117 118 enum ParseMode { // ### keep in sync with CPlusPlus::TranslationUnit 119 ParseTranlationUnit, 120 ParseDeclaration, 121 ParseExpression, 122 ParseDeclarator, 123 ParseStatement 124 }; 125 126 bool isTokenized() const; 127 void tokenize(); 128 129 bool isParsed() const; 130 bool parse(ParseMode mode = ParseTranlationUnit); 131 132 enum CheckMode { 133 Unchecked, 134 FullCheck, 135 FastCheck 136 }; 137 138 void check(CheckMode mode = FullCheck); 139 140 static Ptr create(const QString &fileName); 141 142 class CPLUSPLUS_EXPORT DiagnosticMessage 143 { 144 public: 145 enum Level { 146 Warning, 147 Error, 148 Fatal 149 }; 150 151 public: 152 DiagnosticMessage(int level, const QString &fileName, 153 int line, int column, 154 const QString &text, 155 int length = 0) _level(level)156 : _level(level), 157 _line(line), 158 _fileName(fileName), 159 _column(column), 160 _length(length), 161 _text(text) 162 { } 163 level()164 int level() const 165 { return _level; } 166 isWarning()167 bool isWarning() const 168 { return _level == Warning; } 169 isError()170 bool isError() const 171 { return _level == Error; } 172 isFatal()173 bool isFatal() const 174 { return _level == Fatal; } 175 fileName()176 QString fileName() const 177 { return _fileName; } 178 line()179 int line() const 180 { return _line; } 181 column()182 int column() const 183 { return _column; } 184 length()185 int length() const 186 { return _length; } 187 text()188 QString text() const 189 { return _text; } 190 191 bool operator==(const DiagnosticMessage &other) const; 192 bool operator!=(const DiagnosticMessage &other) const; 193 194 private: 195 int _level; 196 int _line; 197 QString _fileName; 198 int _column; 199 int _length; 200 QString _text; 201 }; 202 addDiagnosticMessage(const DiagnosticMessage & d)203 void addDiagnosticMessage(const DiagnosticMessage &d) 204 { _diagnosticMessages.append(d); } 205 clearDiagnosticMessages()206 void clearDiagnosticMessages() 207 { _diagnosticMessages.clear(); } 208 diagnosticMessages()209 QList<DiagnosticMessage> diagnosticMessages() const 210 { return _diagnosticMessages; } 211 212 class Block 213 { 214 int _bytesBegin; 215 int _bytesEnd; 216 int _utf16charsBegin; 217 int _utf16charsEnd; 218 219 public: 220 inline Block(int bytesBegin = 0, int bytesEnd = 0, 221 int utf16charsBegin = 0, int utf16charsEnd = 0) _bytesBegin(bytesBegin)222 : _bytesBegin(bytesBegin), 223 _bytesEnd(bytesEnd), 224 _utf16charsBegin(utf16charsBegin), 225 _utf16charsEnd(utf16charsEnd) 226 {} 227 bytesBegin()228 inline int bytesBegin() const 229 { return _bytesBegin; } 230 bytesEnd()231 inline int bytesEnd() const 232 { return _bytesEnd; } 233 utf16charsBegin()234 inline int utf16charsBegin() const 235 { return _utf16charsBegin; } 236 utf16charsEnd()237 inline int utf16charsEnd() const 238 { return _utf16charsEnd; } 239 containsUtf16charOffset(int utf16charOffset)240 bool containsUtf16charOffset(int utf16charOffset) const 241 { return utf16charOffset >= _utf16charsBegin && utf16charOffset < _utf16charsEnd; } 242 }; 243 244 class Include { 245 QString _resolvedFileName; 246 QString _unresolvedFileName; 247 int _line; 248 Client::IncludeType _type; 249 250 public: Include(const QString & unresolvedFileName,const QString & resolvedFileName,int line,Client::IncludeType type)251 Include(const QString &unresolvedFileName, const QString &resolvedFileName, int line, 252 Client::IncludeType type) 253 : _resolvedFileName(resolvedFileName) 254 , _unresolvedFileName(unresolvedFileName) 255 , _line(line) 256 , _type(type) 257 { } 258 resolvedFileName()259 QString resolvedFileName() const 260 { return _resolvedFileName; } 261 unresolvedFileName()262 QString unresolvedFileName() const 263 { return _unresolvedFileName; } 264 line()265 int line() const 266 { return _line; } 267 type()268 Client::IncludeType type() const 269 { return _type; } 270 }; 271 272 class MacroUse: public Block { 273 Macro _macro; 274 QVector<Block> _arguments; 275 int _beginLine; 276 277 public: MacroUse(const Macro & macro,int bytesBegin,int bytesEnd,int utf16charsBegin,int utf16charsEnd,int beginLine)278 inline MacroUse(const Macro ¯o, 279 int bytesBegin, int bytesEnd, 280 int utf16charsBegin, int utf16charsEnd, 281 int beginLine) 282 : Block(bytesBegin, bytesEnd, utf16charsBegin, utf16charsEnd), 283 _macro(macro), 284 _beginLine(beginLine) 285 { } 286 macro()287 const Macro ¯o() const 288 { return _macro; } 289 isFunctionLike()290 bool isFunctionLike() const 291 { return _macro.isFunctionLike(); } 292 arguments()293 QVector<Block> arguments() const 294 { return _arguments; } 295 beginLine()296 int beginLine() const 297 { return _beginLine; } 298 299 private: addArgument(const Block & block)300 void addArgument(const Block &block) 301 { _arguments.append(block); } 302 303 friend class Document; 304 }; 305 306 class UndefinedMacroUse: public Block { 307 QByteArray _name; 308 309 public: UndefinedMacroUse(const QByteArray & name,int bytesBegin,int utf16charsBegin)310 inline UndefinedMacroUse( 311 const QByteArray &name, 312 int bytesBegin, 313 int utf16charsBegin) 314 : Block(bytesBegin, 315 bytesBegin + name.length(), 316 utf16charsBegin, 317 utf16charsBegin + QString::fromUtf8(name, name.size()).size()), 318 _name(name) 319 { } 320 name()321 QByteArray name() const 322 { 323 return _name; 324 } 325 }; 326 327 QStringList includedFiles() const; 328 void addIncludeFile(const Include &include); 329 resolvedIncludes()330 QList<Include> resolvedIncludes() const 331 { return _resolvedIncludes; } 332 unresolvedIncludes()333 QList<Include> unresolvedIncludes() const 334 { return _unresolvedIncludes; } 335 skippedBlocks()336 QList<Block> skippedBlocks() const 337 { return _skippedBlocks; } 338 macroUses()339 QList<MacroUse> macroUses() const 340 { return _macroUses; } 341 undefinedMacroUses()342 QList<UndefinedMacroUse> undefinedMacroUses() const 343 { return _undefinedMacroUses; } 344 setIncludeGuardMacroName(const QByteArray & includeGuardMacroName)345 void setIncludeGuardMacroName(const QByteArray &includeGuardMacroName) 346 { _includeGuardMacroName = includeGuardMacroName; } includeGuardMacroName()347 QByteArray includeGuardMacroName() const 348 { return _includeGuardMacroName; } 349 350 const Macro *findMacroDefinitionAt(int line) const; 351 const MacroUse *findMacroUseAt(int utf16charsOffset) const; 352 const UndefinedMacroUse *findUndefinedMacroUseAt(int utf16charsOffset) const; 353 354 void keepSourceAndAST(); 355 void releaseSourceAndAST(); 356 checkMode()357 CheckMode checkMode() const 358 { return static_cast<CheckMode>(_checkMode); } 359 360 private: 361 QString _fileName; 362 Control *_control; 363 TranslationUnit *_translationUnit; 364 Namespace *_globalNamespace; 365 366 /// All messages generated during lexical/syntactic/semantic analysis. 367 QList<DiagnosticMessage> _diagnosticMessages; 368 369 QList<Include> _resolvedIncludes; 370 QList<Include> _unresolvedIncludes; 371 QList<Macro> _definedMacros; 372 QList<Block> _skippedBlocks; 373 QList<MacroUse> _macroUses; 374 QList<UndefinedMacroUse> _undefinedMacroUses; 375 376 /// the macro name of the include guard, if there is one. 377 QByteArray _includeGuardMacroName; 378 379 QByteArray m_fingerprint; 380 381 QByteArray _source; 382 QDateTime _lastModified; 383 QAtomicInt _keepSourceAndASTCount; 384 unsigned _revision; 385 unsigned _editorRevision; 386 quint8 _checkMode; 387 388 friend class Snapshot; 389 }; 390 391 class CPLUSPLUS_EXPORT Snapshot 392 { 393 typedef QHash<Utils::FilePath, Document::Ptr> Base; 394 395 public: 396 Snapshot(); 397 ~Snapshot(); 398 399 typedef Base::const_iterator iterator; 400 typedef Base::const_iterator const_iterator; 401 typedef QPair<Document::Ptr, int> IncludeLocation; 402 403 int size() const; // ### remove 404 bool isEmpty() const; 405 406 void insert(Document::Ptr doc); // ### remove 407 void remove(const Utils::FilePath &fileName); // ### remove remove(const QString & fileName)408 void remove(const QString &fileName) 409 { remove(Utils::FilePath::fromString(fileName)); } 410 begin()411 const_iterator begin() const { return _documents.begin(); } end()412 const_iterator end() const { return _documents.end(); } 413 414 bool contains(const Utils::FilePath &fileName) const; contains(const QString & fileName)415 bool contains(const QString &fileName) const 416 { return contains(Utils::FilePath::fromString(fileName)); } 417 418 Document::Ptr document(const Utils::FilePath &fileName) const; document(const QString & fileName)419 Document::Ptr document(const QString &fileName) const 420 { return document(Utils::FilePath::fromString(fileName)); } 421 422 const_iterator find(const Utils::FilePath &fileName) const; find(const QString & fileName)423 const_iterator find(const QString &fileName) const 424 { return find(Utils::FilePath::fromString(fileName)); } 425 426 Snapshot simplified(Document::Ptr doc) const; 427 428 Document::Ptr preprocessedDocument(const QByteArray &source, 429 const Utils::FilePath &fileName, 430 int withDefinedMacrosFromDocumentUntilLine = -1) const; 431 Document::Ptr preprocessedDocument(const QByteArray &source, 432 const QString &fileName, 433 int withDefinedMacrosFromDocumentUntilLine = -1) const 434 { 435 return preprocessedDocument(source, 436 Utils::FilePath::fromString(fileName), 437 withDefinedMacrosFromDocumentUntilLine); 438 } 439 440 Document::Ptr documentFromSource(const QByteArray &preprocessedDocument, 441 const QString &fileName) const; 442 443 QSet<QString> allIncludesForDocument(const QString &fileName) const; 444 QList<IncludeLocation> includeLocationsOfDocument(const QString &fileName) const; 445 446 Utils::FilePaths filesDependingOn(const Utils::FilePath &fileName) const; filesDependingOn(const QString & fileName)447 Utils::FilePaths filesDependingOn(const QString &fileName) const 448 { return filesDependingOn(Utils::FilePath::fromString(fileName)); } 449 void updateDependencyTable() const; 450 void updateDependencyTable(QFutureInterfaceBase &futureInterface) const; 451 452 bool operator==(const Snapshot &other) const; 453 454 private: 455 mutable DependencyTable m_deps; 456 Base _documents; 457 }; 458 459 } // namespace CPlusPlus 460