diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp index 0dd5f745..914074c4 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp @@ -680,96 +680,12 @@ ParseLocation CxxAstVisitor::getParseLocationOfFunctionBody(const clang::Functio ParseLocation CxxAstVisitor::getParseLocation(const clang::SourceLocation& sourceLocation) const { - ParseLocation parseLocation; - if (sourceLocation.isValid()) - { - const clang::SourceManager& sourceManager = m_astContext->getSourceManager(); - - clang::SourceLocation loc = sourceLocation; - if (sourceManager.isMacroBodyExpansion(sourceLocation)) - { - loc = sourceManager.getExpansionLoc(sourceLocation); - if (loc.isInvalid()) - { - loc = sourceLocation; - } - } - - const clang::SourceLocation startLoc = sourceManager.getSpellingLoc(loc); - const clang::FileID fileId = sourceManager.getFileID(startLoc); - - // find the location file - parseLocation.filePath = m_canonicalFilePathCache->getCanonicalFilePath(fileId, sourceManager); - - // find the start location - { - const unsigned int offset = sourceManager.getFileOffset(startLoc); - parseLocation.startLineNumber = sourceManager.getLineNumber(fileId, offset); - parseLocation.startColumnNumber = sourceManager.getColumnNumber(fileId, offset); - } - - // General case -- find the end of the token starting at loc. - { - const clang::SourceLocation endSloc = m_preprocessor->getLocForEndOfToken(startLoc); - const unsigned int offset = sourceManager.getFileOffset(endSloc); - parseLocation.endLineNumber = sourceManager.getLineNumber(fileId, offset); - parseLocation.endColumnNumber = sourceManager.getColumnNumber(fileId, offset) - 1; - } - } - - return parseLocation; + return utility::getParseLocation(sourceLocation, m_astContext->getSourceManager(), m_preprocessor, m_canonicalFilePathCache); } ParseLocation CxxAstVisitor::getParseLocation(const clang::SourceRange& sourceRange) const { - ParseLocation parseLocation; - if (sourceRange.isValid()) - { - const clang::SourceManager& sourceManager = m_astContext->getSourceManager(); - - clang::SourceRange range = sourceRange; - clang::SourceLocation endLoc = m_preprocessor->getLocForEndOfToken(range.getEnd()); - - if (( - sourceManager.isMacroArgExpansion(range.getBegin()) || - sourceManager.isMacroBodyExpansion(range.getBegin()) - ) && - ( - sourceManager.isMacroArgExpansion(range.getEnd()) || - sourceManager.isMacroBodyExpansion(range.getEnd()) - )) - { - range = sourceManager.getExpansionRange(sourceRange); - if (range.isValid()) - { - endLoc = m_preprocessor->getLocForEndOfToken(range.getBegin()); - } - else - { - range = sourceRange; - } - } - - const clang::SourceLocation beginLoc = range.getBegin(); - - const clang::PresumedLoc presumedBegin = sourceManager.getPresumedLoc(beginLoc, false); - const clang::PresumedLoc presumedEnd = sourceManager.getPresumedLoc(endLoc.isValid() ? endLoc : range.getEnd(), false); - - FilePath filePath = m_canonicalFilePathCache->getCanonicalFilePath(sourceManager.getFileID(beginLoc), sourceManager); - if (filePath.empty()) - { - filePath = m_canonicalFilePathCache->getCanonicalFilePath(utility::decodeFromUtf8(presumedBegin.getFilename())); - } - - parseLocation = ParseLocation( - filePath, - presumedBegin.getLine(), - presumedBegin.getColumn(), - presumedEnd.getLine(), - presumedEnd.getColumn() - (endLoc.isValid() ? 1 : 0) - ); - } - return parseLocation; + return utility::getParseLocation(sourceRange, m_astContext->getSourceManager(), m_preprocessor, m_canonicalFilePathCache); } bool CxxAstVisitor::shouldVisitStmt(const clang::Stmt* s) const diff --git a/src/lib_cxx/data/parser/cxx/CxxDiagnosticConsumer.cpp b/src/lib_cxx/data/parser/cxx/CxxDiagnosticConsumer.cpp index e97442bb..ab4e9b4f 100644 --- a/src/lib_cxx/data/parser/cxx/CxxDiagnosticConsumer.cpp +++ b/src/lib_cxx/data/parser/cxx/CxxDiagnosticConsumer.cpp @@ -69,18 +69,10 @@ void CxxDiagnosticConsumer::HandleDiagnostic(clang::DiagnosticsEngine::Level lev return; } - FilePath filePath; - uint line = 0; - uint column = 0; - + ParseLocation location(FilePath(), 0, 0); if (info.getLocation().isValid() && info.hasSourceManager()) { const clang::SourceManager& sourceManager = info.getSourceManager(); - { - const clang::PresumedLoc presumedLocation = sourceManager.getPresumedLoc(info.getLocation()); - line = presumedLocation.getLine(); - column = presumedLocation.getColumn(); - } clang::SourceLocation loc = sourceManager.getExpansionLoc(info.getLocation()); if (loc.isInvalid()) @@ -88,26 +80,31 @@ void CxxDiagnosticConsumer::HandleDiagnostic(clang::DiagnosticsEngine::Level lev loc = info.getLocation(); } - const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(sourceManager.getFileID(loc)); - if (fileEntry == nullptr || !fileEntry->isValid()) - { - fileEntry = sourceManager.getFileEntryForID(sourceManager.getMainFileID()); - } + clang::FileID fileId = sourceManager.getFileID(loc); + const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId); if (fileEntry != nullptr && fileEntry->isValid()) { - filePath = m_canonicalFilePathCache->getCanonicalFilePath(fileEntry); + location = utility::getParseLocation(loc, sourceManager, nullptr, m_canonicalFilePathCache); + } + else + { + fileEntry = sourceManager.getFileEntryForID(sourceManager.getMainFileID()); + if (fileEntry != nullptr && fileEntry->isValid()) + { + location = ParseLocation(m_canonicalFilePathCache->getCanonicalFilePath(fileEntry), 1, 1); + } } } - - ParseLocation location(filePath, line, column); - - m_client->recordError( - location, - utility::decodeFromUtf8(message), - level == clang::DiagnosticsEngine::Fatal, - m_canonicalFilePathCache->getFileRegister()->hasFilePath(location.filePath), - m_sourceFilePath - ); + if (location.isValid()) + { + m_client->recordError( + location, + utility::decodeFromUtf8(message), + level == clang::DiagnosticsEngine::Fatal, + m_canonicalFilePathCache->getFileRegister()->hasFilePath(location.filePath), + m_sourceFilePath + ); + } } } diff --git a/src/lib_cxx/data/parser/cxx/utilityClang.cpp b/src/lib_cxx/data/parser/cxx/utilityClang.cpp index b843dbef..fdd51489 100644 --- a/src/lib_cxx/data/parser/cxx/utilityClang.cpp +++ b/src/lib_cxx/data/parser/cxx/utilityClang.cpp @@ -2,7 +2,10 @@ #include #include +#include +#include "data/parser/cxx/CanonicalFilePathCache.h" +#include "data/parser/ParseLocation.h" #include "utility/file/FilePath.h" #include "utility/utilityString.h" @@ -126,3 +129,109 @@ std::wstring utility::getFileNameOfFileEntry(const clang::FileEntry* entry) } return fileName; } + +ParseLocation utility::getParseLocation( + const clang::SourceLocation& sourceLocation, + const clang::SourceManager& sourceManager, + clang::Preprocessor* preprocessor, + std::shared_ptr canonicalFilePathCache) +{ + ParseLocation parseLocation; + if (sourceLocation.isValid()) + { + clang::SourceLocation loc = sourceLocation; + if (sourceManager.isMacroBodyExpansion(sourceLocation)) + { + loc = sourceManager.getExpansionLoc(sourceLocation); + if (loc.isInvalid()) + { + loc = sourceLocation; + } + } + + const clang::SourceLocation startLoc = sourceManager.getSpellingLoc(loc); + const clang::FileID fileId = sourceManager.getFileID(startLoc); + + // find the location file + parseLocation.filePath = canonicalFilePathCache->getCanonicalFilePath(fileId, sourceManager); + + // find the start location + { + const unsigned int offset = sourceManager.getFileOffset(startLoc); + parseLocation.startLineNumber = sourceManager.getLineNumber(fileId, offset); + parseLocation.startColumnNumber = sourceManager.getColumnNumber(fileId, offset); + } + + // General case -- find the end of the token starting at loc. + if (preprocessor != nullptr) + { + const clang::SourceLocation endSloc = preprocessor->getLocForEndOfToken(startLoc); + const unsigned int offset = sourceManager.getFileOffset(endSloc); + parseLocation.endLineNumber = sourceManager.getLineNumber(fileId, offset); + parseLocation.endColumnNumber = sourceManager.getColumnNumber(fileId, offset) - 1; + } + else + { + parseLocation.endLineNumber = parseLocation.startLineNumber; + parseLocation.endColumnNumber = parseLocation.startColumnNumber; + } + } + + return parseLocation; +} + + +ParseLocation utility::getParseLocation( + const clang::SourceRange& sourceRange, + const clang::SourceManager& sourceManager, + clang::Preprocessor* preprocessor, + std::shared_ptr canonicalFilePathCache) +{ + ParseLocation parseLocation; + if (sourceRange.isValid()) + { + clang::SourceRange range = sourceRange; + clang::SourceLocation endLoc = preprocessor->getLocForEndOfToken(range.getEnd()); + + if ( + ( + sourceManager.isMacroArgExpansion(range.getBegin()) || + sourceManager.isMacroBodyExpansion(range.getBegin()) + ) && + ( + sourceManager.isMacroArgExpansion(range.getEnd()) || + sourceManager.isMacroBodyExpansion(range.getEnd()) + ) + ){ + range = sourceManager.getExpansionRange(sourceRange); + if (range.isValid()) + { + endLoc = preprocessor->getLocForEndOfToken(range.getBegin()); + } + else + { + range = sourceRange; + } + } + + const clang::SourceLocation beginLoc = range.getBegin(); + + const clang::PresumedLoc presumedBegin = sourceManager.getPresumedLoc(beginLoc, false); + const clang::PresumedLoc presumedEnd = sourceManager.getPresumedLoc(endLoc.isValid() ? endLoc : range.getEnd(), false); + + FilePath filePath = canonicalFilePathCache->getCanonicalFilePath(sourceManager.getFileID(beginLoc), sourceManager); + if (filePath.empty()) + { + filePath = canonicalFilePathCache->getCanonicalFilePath(utility::decodeFromUtf8(presumedBegin.getFilename())); + } + + parseLocation = ParseLocation( + filePath, + presumedBegin.getLine(), + presumedBegin.getColumn(), + presumedEnd.getLine(), + presumedEnd.getColumn() - (endLoc.isValid() ? 1 : 0) + ); + } + return parseLocation; +} diff --git a/src/lib_cxx/data/parser/cxx/utilityClang.h b/src/lib_cxx/data/parser/cxx/utilityClang.h index fca5df73..1f3eb2e1 100644 --- a/src/lib_cxx/data/parser/cxx/utilityClang.h +++ b/src/lib_cxx/data/parser/cxx/utilityClang.h @@ -6,6 +6,16 @@ #include "data/parser/AccessKind.h" #include "data/parser/SymbolKind.h" +struct ParseLocation; +class CanonicalFilePathCache; + +namespace clang +{ + class SourceRange; + class Preprocessor; + class SourceManager; +} + namespace utility { template @@ -15,6 +25,18 @@ namespace utility SymbolKind convertTagKind(const clang::TagTypeKind tagKind); SymbolKind getSymbolKind(const clang::VarDecl* d); std::wstring getFileNameOfFileEntry(const clang::FileEntry* entry); + + ParseLocation getParseLocation( + const clang::SourceLocation& sourceLocation, + const clang::SourceManager& sourceManager, + clang::Preprocessor* preprocessor, + std::shared_ptr canonicalFilePathCache); + + ParseLocation getParseLocation( + const clang::SourceRange& sourceRange, + const clang::SourceManager& sourceManager, + clang::Preprocessor* preprocessor, + std::shared_ptr canonicalFilePathCache); } template diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 5ac73d3d..a75075cb 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -4323,15 +4323,27 @@ public: )); } - void test_cxx_parser_catches_error_in_macro_expasdsadansion() + void test_cxx_parser_catches_error_in_force_include() { std::shared_ptr client = parseCode( "void foo() {} \n", { L"-include nothing" } ); TS_ASSERT(utility::containsElement( - client->errors, L"' nothing' file not found <1:10 1:10>" - )); + client->errors, L"' nothing' file not found <1:1 1:1>" + )); + } + + void test_cxx_parser_finds_correct_error_location_after_line_directive() + { + std::shared_ptr client = parseCode( + "#line 55 \"foo.hpp\"\n" + "void foo()\n" + ); + + TS_ASSERT(utility::containsElement( + client->errors, L"expected function body after function declarator <2:11 2:11>" + )); } void test_cxx_parser_catches_error_in_macro_expansion()