logic: fixed recorded locations of errors that appear after cxx line directives (issue #610)

This commit is contained in:
mlangkabel
2018-08-24 16:06:05 +02:00
parent f7e67c8a63
commit 862f7b99a7
5 changed files with 170 additions and 114 deletions
+2 -86
View File
@@ -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>
+15 -3
View File
@@ -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()