logic: fixed recorded locations of errors that appear after cxx line directives (issue #610)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
#include <clang/AST/DeclCXX.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
#include <clang/Lex/Preprocessor.h>
|
||||
|
||||
#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> 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> 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;
|
||||
}
|
||||
|
||||
@@ -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 <typename T>
|
||||
@@ -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> canonicalFilePathCache);
|
||||
|
||||
ParseLocation getParseLocation(
|
||||
const clang::SourceRange& sourceRange,
|
||||
const clang::SourceManager& sourceManager,
|
||||
clang::Preprocessor* preprocessor,
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -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<TestParserClient> client = parseCode(
|
||||
"void foo() {} \n", { L"-include nothing" }
|
||||
);
|
||||
|
||||
TS_ASSERT(utility::containsElement<std::wstring>(
|
||||
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<TestParserClient> client = parseCode(
|
||||
"#line 55 \"foo.hpp\"\n"
|
||||
"void foo()\n"
|
||||
);
|
||||
|
||||
TS_ASSERT(utility::containsElement<std::wstring>(
|
||||
client->errors, L"expected function body after function declarator <2:11 2:11>"
|
||||
));
|
||||
}
|
||||
|
||||
void test_cxx_parser_catches_error_in_macro_expansion()
|
||||
|
||||
Reference in New Issue
Block a user