Files
qt-creator/src/tools/clangrefactoringbackend/source/macropreprocessorcallbacks.h
Marco Bubke 4cdb5bab15 Clang: Add clang refactoring
Change-Id: I2e3f36f810276da3f8dc7dcc587b06f8edb586d3
GPush-Base: d02f51b48fc752fddcdef6dcb32b3f7f6c0195a3
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
2016-08-04 14:37:19 +00:00

193 lines
7.0 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "sourcelocationsutils.h"
#include <sourcelocationscontainer.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/Basic/SourceManager.h>
#include <clang/Lex/PPCallbacks.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/MacroInfo.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#include <QDebug>
namespace ClangBackEnd {
struct MacroDirectiveToken
{
MacroDirectiveToken(const clang::MacroDirective *macroDirective,
const clang::Token &token)
: macroDirective(macroDirective),
token(token)
{}
const clang::MacroDirective *macroDirective;
const clang::Token token;
};
class MacroPreprocessorCallbacks : public clang::PPCallbacks
{
public:
MacroPreprocessorCallbacks(SourceLocationsContainer &sourceLocationsContainer,
Utils::SmallString &symbolName,
clang::Preprocessor &preprocessor,
uint line,
uint column);
void FileChanged(clang::SourceLocation location,
FileChangeReason reason,
clang::SrcMgr::CharacteristicKind /*fileType*/,
clang::FileID /*previousFileIdentifier*/) final
{
if (!isMainFileEntered) {
updateLocations();
updateIsMainFileEntered(location, reason);
}
}
void MacroDefined(const clang::Token &token, const clang::MacroDirective *macroDirective) final
{
if (isInMainFile(token)) {
if (includesCursorPosition(token)) {
sourceLocations.push_back(token.getLocation());
cursorMacroDirective = macroDirective;
symbolName = Utils::SmallString(token.getIdentifierInfo()->getNameStart(),
token.getIdentifierInfo()->getLength());
}
}
}
void MacroExpands(const clang::Token &token,
const clang::MacroDefinition &macroDefinition,
clang::SourceRange /*sourceRange*/,
const clang::MacroArgs * /*macroArguments*/) final
{
if (includesCursorPosition(token)) {
appendSourceLocations(token, macroDefinition);
cursorMacroDirective = macroDefinition.getLocalDirective();
symbolName = Utils::SmallString(token.getIdentifierInfo()->getNameStart(),
token.getIdentifierInfo()->getLength());
} else if (isCurrentTokenExpansion(macroDefinition)) {
sourceLocations.push_back(token.getLocation());
} else if (isBeforeCursorSourceLocation()) {
preCursorMacroDirectiveTokens.emplace_back(macroDefinition.getLocalDirective(), token);
}
}
void EndOfMainFile() final
{
appendSourceLocationsToSourceLocationsContainer(sourceLocationsContainer,
sourceLocations,
sourceManager());
}
private:
void appendSourceLocations(const clang::Token &token,
const clang::MacroDefinition &macroDefinition)
{
sourceLocations.push_back(macroDefinition.getLocalDirective()->getLocation());
for (const auto &macroDirectiveToken : preCursorMacroDirectiveTokens) {
if (macroDirectiveToken.macroDirective == macroDefinition.getLocalDirective())
sourceLocations.push_back(macroDirectiveToken.token.getLocation());
}
sourceLocations.push_back(token.getLocation());
}
void updateLocations()
{
if (mainFileSourceLocation.isInvalid()) {
mainFileSourceLocation = sourceManager().getLocForStartOfFile(sourceManager().getMainFileID());
cursorSourceLocation = sourceManager().translateLineCol(sourceManager().getMainFileID(),
line,
column);
}
}
void updateIsMainFileEntered(clang::SourceLocation location, FileChangeReason reason)
{
if (location == mainFileSourceLocation && reason == PPCallbacks::EnterFile)
isMainFileEntered = true;
}
const clang::SourceManager &sourceManager() const
{
return preprocessor.getSourceManager();
}
bool isInMainFile(const clang::Token &token)
{
return isMainFileEntered && sourceManager().isWrittenInMainFile(token.getLocation());
}
bool includesCursorPosition(const clang::Token &token)
{
auto start = token.getLocation();
auto end = token.getEndLoc();
return cursorSourceLocation == start
|| cursorSourceLocation == end
|| (sourceManager().isBeforeInTranslationUnit(start, cursorSourceLocation) &&
sourceManager().isBeforeInTranslationUnit(cursorSourceLocation, end));
}
bool isCurrentTokenExpansion(const clang::MacroDefinition &macroDefinition)
{
return cursorMacroDirective
&& cursorMacroDirective == macroDefinition.getLocalDirective();
}
bool isBeforeCursorSourceLocation() const
{
return !cursorMacroDirective;
}
private:
std::vector<clang::SourceLocation> sourceLocations;
std::vector<MacroDirectiveToken> preCursorMacroDirectiveTokens;
SourceLocationsContainer &sourceLocationsContainer;
Utils::SmallString &symbolName;
clang::Preprocessor &preprocessor;
const clang::MacroDirective *cursorMacroDirective = nullptr;
clang::SourceLocation mainFileSourceLocation;
clang::SourceLocation cursorSourceLocation;
uint line;
uint column;
bool isMainFileEntered = false;
};
} // namespace ClangBackEnd