Clang: Add clang refactoring

Change-Id: I2e3f36f810276da3f8dc7dcc587b06f8edb586d3
GPush-Base: d02f51b48fc752fddcdef6dcb32b3f7f6c0195a3
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2016-08-04 15:26:53 +02:00
parent 2b9edb35ea
commit 4cdb5bab15
103 changed files with 5434 additions and 112 deletions

View File

@@ -0,0 +1,23 @@
INCLUDEPATH += $$PWD
SOURCES += \
$$PWD/refactoringcompilationdatabase.cpp \
$$PWD/symbolfinder.cpp \
$$PWD/symbollocationfinderaction.cpp \
$$PWD/refactoringserver.cpp \
$$PWD/sourcefilecallbacks.cpp \
$$PWD/macropreprocessorcallbacks.cpp \
$$PWD/findusrforcursoraction.cpp
HEADERS += \
$$PWD/refactoringcompilationdatabase.h \
$$PWD/clangrefactoringbackend_global.h \
$$PWD/symbolfinder.h \
$$PWD/symbollocationfinderaction.h \
$$PWD/refactoringserver.h \
$$PWD/sourcefilecallbacks.h \
$$PWD/macropreprocessorcallbacks.h \
$$PWD/sourcelocationsutils.h \
$$PWD/findcursorusr.h \
$$PWD/findusrforcursoraction.h \
$$PWD/findlocationsofusrs.h

View File

@@ -0,0 +1,44 @@
/****************************************************************************
**
** 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
namespace llvm {
template <typename T, unsigned N>
class SmallVector;
}
namespace ClangBackEnd {
using USRName = llvm::SmallVector<char, 128>;
// use std::filesystem::path if it is supported by all compilers
#ifdef WIN32
const char nativeSeperator = '\\';
#else
const char nativeSeperator = '/';
#endif
}

View File

@@ -0,0 +1,198 @@
/****************************************************************************
**
** 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
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/AST/AST.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Index/USRGeneration.h>
#include <llvm/ADT/SmallVector.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#include <vector>
namespace ClangBackEnd {
class FindNamedDeclarationASTVisitor : public clang::RecursiveASTVisitor<FindNamedDeclarationASTVisitor>
{
public:
explicit FindNamedDeclarationASTVisitor(const clang::SourceManager &sourceManager,
const clang::SourceLocation cursorSourceLocation)
: sourceManager(sourceManager),
cursorSourceLocation(cursorSourceLocation)
{
}
bool shouldVisitTemplateInstantiations() const
{
return true;
}
bool shouldVisitImplicitCode() const
{
return true;
}
bool VisitNamedDecl(const clang::NamedDecl *declaration)
{
auto name = declaration->getNameAsString();
return setResultIfCursorIsInBetween(declaration, declaration->getLocation(),
declaration->getNameAsString().length());
}
bool VisitDeclRefExpr(const clang::DeclRefExpr *expression)
{
if (!iterateNestedNameSpecifierLocation(expression->getQualifierLoc()))
return false;
const auto *Decl = expression->getFoundDecl();
return setResultIfCursorIsInBetween(Decl, expression->getLocation(),
Decl->getNameAsString().length());
}
bool VisitMemberExpr(const clang::MemberExpr *Expr)
{
const auto *Decl = Expr->getFoundDecl().getDecl();
return setResultIfCursorIsInBetween(Decl, Expr->getMemberLoc(),
Decl->getNameAsString().length());
}
std::vector<const clang::NamedDecl*> takeNamedDecl()
{
return std::move(namedDeclarations);
}
private:
bool canSetResult(const clang::NamedDecl *declaration,
clang::SourceLocation location)
{
return declaration
&& !setResultIfCursorIsInBetween(declaration,
location,
declaration->getNameAsString().length());
}
bool iterateNestedNameSpecifierLocation(clang::NestedNameSpecifierLoc nameLocation) {
while (nameLocation) {
const auto *declaration = nameLocation.getNestedNameSpecifier()->getAsNamespace();
if (canSetResult(declaration, nameLocation.getLocalBeginLoc()))
return false;
nameLocation = nameLocation.getPrefix();
}
return true;
}
bool isValidLocationWithCursorInside(clang::SourceLocation startLocation,
clang::SourceLocation endLocation)
{
return startLocation.isValid()
&& startLocation.isFileID()
&& endLocation.isValid()
&& endLocation.isFileID()
&& isCursorLocationBetween(startLocation, endLocation);
}
bool setResultIfCursorIsInBetween(const clang::NamedDecl *declaration,
clang::SourceLocation startLocation,
clang::SourceLocation endLocation)
{
bool isValid = isValidLocationWithCursorInside(startLocation, endLocation);
if (isValid)
namedDeclarations.push_back(declaration);
return !isValid;
}
bool setResultIfCursorIsInBetween(const clang::NamedDecl *declaration,
clang::SourceLocation location,
uint offset) {
return offset == 0
|| setResultIfCursorIsInBetween(declaration, location, location.getLocWithOffset(offset - 1));
}
bool isCursorLocationBetween(const clang::SourceLocation startLocation,
const clang::SourceLocation endLocation)
{
return cursorSourceLocation == startLocation
|| cursorSourceLocation == endLocation
|| (sourceManager.isBeforeInTranslationUnit(startLocation, cursorSourceLocation)
&& sourceManager.isBeforeInTranslationUnit(cursorSourceLocation, endLocation));
}
std::vector<const clang::NamedDecl*> namedDeclarations;
const clang::SourceManager &sourceManager;
const clang::SourceLocation cursorSourceLocation; // The location to find the NamedDecl.
};
inline
std::vector<const clang::NamedDecl *> namedDeclarationsAt(const clang::ASTContext &Context,
const clang::SourceLocation cursorSourceLocation)
{
const auto &sourceManager = Context.getSourceManager();
const auto currentFile = sourceManager.getFilename(cursorSourceLocation);
FindNamedDeclarationASTVisitor visitor(sourceManager, cursorSourceLocation);
auto declarations = Context.getTranslationUnitDecl()->decls();
for (auto &currentDeclation : declarations) {
const auto &fileLocation = currentDeclation->getLocStart();
const auto &fileName = sourceManager.getFilename(fileLocation);
if (fileName == currentFile) {
visitor.TraverseDecl(currentDeclation);
const auto &namedDeclarations = visitor.takeNamedDecl();
if (!namedDeclarations.empty())
return namedDeclarations;
}
}
return std::vector<const clang::NamedDecl *>();
}
inline
USRName USROfDeclaration(const clang::Decl *declaration)
{
USRName buffer;
if (declaration == nullptr || clang::index::generateUSRForDecl(declaration, buffer))
return buffer;
return buffer;
}
} // namespace ClangBackend

View File

@@ -0,0 +1,134 @@
/****************************************************************************
**
** 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 "findcursorusr.h"
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Basic/SourceLocation.h>
#include <clang/Index/USRGeneration.h>
#include <llvm/ADT/SmallVector.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#include <vector>
namespace ClangBackEnd {
class FindLocationsOfUSRsASTVisitor : public clang::RecursiveASTVisitor<FindLocationsOfUSRsASTVisitor>
{
public:
explicit FindLocationsOfUSRsASTVisitor(std::vector<USRName> &unifiedSymbolResolutions)
: unifiedSymbolResolutions(unifiedSymbolResolutions)
{
std::sort(unifiedSymbolResolutions.begin(), unifiedSymbolResolutions.end());
}
bool VisitNamedDecl(const clang::NamedDecl *declaration) {
auto declarationUSR = USROfDeclaration(declaration);
if (containsUSR(declarationUSR))
LocationsFound.push_back(declaration->getLocation());
return true;
}
bool VisitDeclRefExpr(const clang::DeclRefExpr *expression) {
const auto *declaration = expression->getFoundDecl();
iterateNestedNameSpecifierLocation(expression->getQualifierLoc());
auto declarationUSR = USROfDeclaration(declaration);
if (containsUSR(declarationUSR))
LocationsFound.push_back(expression->getLocation());
return true;
}
bool VisitMemberExpr(const clang::MemberExpr *expression) {
const auto *declaration = expression->getFoundDecl().getDecl();
auto declarationUSR = USROfDeclaration(declaration);
if (containsUSR(declarationUSR))
LocationsFound.push_back(expression->getMemberLoc());
return true;
}
bool shouldVisitTemplateInstantiations() const
{
return true;
}
std::vector<clang::SourceLocation> takeFoundLocations() const {
return std::move(LocationsFound);
}
private:
void iterateNestedNameSpecifierLocation(clang::NestedNameSpecifierLoc nameLocation) {
while (nameLocation) {
const auto *declaration = nameLocation.getNestedNameSpecifier()->getAsNamespace();
if (declaration && containsUSR(USROfDeclaration(declaration)))
LocationsFound.push_back(nameLocation.getLocalBeginLoc());
nameLocation = nameLocation.getPrefix();
}
}
bool containsUSR(const USRName &unifiedSymbolResolution)
{
return std::binary_search(unifiedSymbolResolutions.cbegin(),
unifiedSymbolResolutions.cend(),
unifiedSymbolResolution);
}
private:
// All the locations of the USR were found.
std::vector<USRName> unifiedSymbolResolutions;
std::vector<clang::SourceLocation> LocationsFound;
};
inline
std::vector<clang::SourceLocation> takeLocationsOfUSRs(std::vector<USRName> &unifiedSymbolResolutions,
clang::Decl *declartation)
{
FindLocationsOfUSRsASTVisitor visitor(unifiedSymbolResolutions);
visitor.TraverseDecl(declartation);
return visitor.takeFoundLocations();
}
} // namespace ClangBackend

View File

@@ -0,0 +1,140 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "findusrforcursoraction.h"
#include "findcursorusr.h"
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#include <algorithm>
#include <vector>
namespace ClangBackEnd {
namespace {
std::vector<USRName> collectConstructorUnifiedSymbolResolutions(const clang::CXXRecordDecl *declarations)
{
std::vector<USRName> unifiedSymbolResolutions;
const auto constructorDeclarations = declarations->getDefinition()->ctors();
std::transform(constructorDeclarations.begin(),
constructorDeclarations.end(),
std::back_inserter(unifiedSymbolResolutions),
USROfDeclaration);
return unifiedSymbolResolutions;
}
void addUnifiedSymbolResolutionsForDeclaration(const std::vector<const clang::NamedDecl *> &declarations,
std::vector<USRName> &usrs)
{
std::transform(declarations.begin(),
declarations.end(),
std::back_inserter(usrs),
[&] (const clang::NamedDecl *declaration) {
return USROfDeclaration(declaration);
});
}
}
class FindDeclarationsConsumer : public clang::ASTConsumer
{
public:
FindDeclarationsConsumer(Utils::SmallString &symbolName,
std::vector<USRName> &unifiedSymbolResolutions,
uint line,
uint column)
: symbolName(symbolName),
unifiedSymbolResolutions(unifiedSymbolResolutions),
line(line),
column(column)
{
}
void HandleTranslationUnit(clang::ASTContext &astContext) override {
const auto &sourceManager = astContext.getSourceManager();
const auto cursorSourceLocation = sourceManager.translateLineCol(sourceManager.getMainFileID(),
line,
column);
if (cursorSourceLocation.isValid())
collectUnifiedSymbolResoltions(astContext, cursorSourceLocation);
}
void collectUnifiedSymbolResoltions(clang::ASTContext &astContext,
const clang::SourceLocation &cursorSourceLocation)
{
const auto foundDeclarations = namedDeclarationsAt(astContext, cursorSourceLocation);
if (!foundDeclarations.empty()) {
const auto firstFoundDeclaration = foundDeclarations.front();
if (const auto *constructorDecl = clang::dyn_cast<clang::CXXConstructorDecl>(firstFoundDeclaration)) {
const clang::CXXRecordDecl *foundDeclarationParent = constructorDecl->getParent();
unifiedSymbolResolutions = collectConstructorUnifiedSymbolResolutions(foundDeclarationParent);
} else if (const auto *destructorDecl = clang::dyn_cast<clang::CXXDestructorDecl>(firstFoundDeclaration)) {
const clang::CXXRecordDecl *foundDeclarationParent = destructorDecl->getParent();
unifiedSymbolResolutions = collectConstructorUnifiedSymbolResolutions(foundDeclarationParent);
} else if (const auto *recordDeclaration = clang::dyn_cast<clang::CXXRecordDecl>(firstFoundDeclaration)) {
unifiedSymbolResolutions = collectConstructorUnifiedSymbolResolutions(recordDeclaration);
}
addUnifiedSymbolResolutionsForDeclaration(foundDeclarations, unifiedSymbolResolutions);
symbolName = firstFoundDeclaration->getNameAsString();
}
}
private:
Utils::SmallString &symbolName;
std::vector<USRName> &unifiedSymbolResolutions;
uint line;
uint column;
};
std::unique_ptr<clang::ASTConsumer>
USRFindingAction::newASTConsumer() {
std::unique_ptr<FindDeclarationsConsumer> Consumer(
new FindDeclarationsConsumer(symbolName, unifiedSymbolResolutions_, line, column));
return std::move(Consumer);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,79 @@
/****************************************************************************
**
** 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 "clangrefactoringbackend_global.h"
#include <utils/smallstring.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "clang/Frontend/FrontendAction.h"
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
namespace clang {
class ASTConsumer;
class CompilerInstance;
class NamedDecl;
}
namespace ClangBackEnd {
class USRFindingAction
{
public:
USRFindingAction(uint line, uint column)
: line(line),
column(column)
{
}
std::unique_ptr<clang::ASTConsumer> newASTConsumer();
std::string takeSymbolName()
{
return std::move(symbolName);
}
std::vector<USRName> takeUnifiedSymbolResolutions()
{
return std::move(unifiedSymbolResolutions_);
}
private:
Utils::SmallString symbolName;
std::vector<USRName> unifiedSymbolResolutions_;
uint line;
uint column;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,43 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "macropreprocessorcallbacks.h"
namespace ClangBackEnd {
MacroPreprocessorCallbacks::MacroPreprocessorCallbacks(SourceLocationsContainer &sourceLocationsContainer,
Utils::SmallString &symbolName,
clang::Preprocessor &preprocessor,
uint line,
uint column)
: sourceLocationsContainer(sourceLocationsContainer),
symbolName(symbolName),
preprocessor(preprocessor),
line(line),
column(column)
{
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,192 @@
/****************************************************************************
**
** 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

View File

@@ -0,0 +1,88 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "refactoringcompilationdatabase.h"
#include "clangrefactoringbackend_global.h"
namespace ClangBackEnd {
RefactoringCompilationDatabase::RefactoringCompilationDatabase()
{
}
namespace {
std::string concatFilePath(const clang::tooling::CompileCommand &compileCommand)
{
return compileCommand.Directory + nativeSeperator + compileCommand.Filename;
}
}
std::vector<clang::tooling::CompileCommand>
RefactoringCompilationDatabase::getCompileCommands(llvm::StringRef filePath) const
{
std::vector<clang::tooling::CompileCommand> foundCommands;
std::copy_if(compileCommands.begin(),
compileCommands.end(),
std::back_inserter(foundCommands),
[&] (const clang::tooling::CompileCommand &compileCommand) {
return filePath == concatFilePath(compileCommand);
});
return foundCommands;
}
std::vector<std::string>
RefactoringCompilationDatabase::getAllFiles() const
{
std::vector<std::string> filePaths;
filePaths.reserve(compileCommands.size());
std::transform(compileCommands.begin(),
compileCommands.end(),
std::back_inserter(filePaths),
[&] (const clang::tooling::CompileCommand &compileCommand) {
return concatFilePath(compileCommand);
});
return filePaths;
}
std::vector<clang::tooling::CompileCommand>
RefactoringCompilationDatabase::getAllCompileCommands() const
{
return compileCommands;
}
void RefactoringCompilationDatabase::addFile(const std::string &directory,
const std::string &fileName,
const std::vector<std::string> &commandLine)
{
compileCommands.emplace_back(directory, fileName, commandLine);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef CLANGBACKEND_REFACTORINGCOMPILATIONDATABASE_H
#define CLANGBACKEND_REFACTORINGCOMPILATIONDATABASE_H
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "clang/Tooling/CompilationDatabase.h"
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
namespace ClangBackEnd {
class RefactoringCompilationDatabase : public clang::tooling::CompilationDatabase
{
public:
RefactoringCompilationDatabase();
std::vector<clang::tooling::CompileCommand> getCompileCommands(llvm::StringRef filePath) const override;
std::vector<std::string> getAllFiles() const override;
std::vector<clang::tooling::CompileCommand> getAllCompileCommands() const override;
void addFile(const std::string &directory,
const std::string &fileName,
const std::vector<std::string> &commandLine);
private:
std::vector<clang::tooling::CompileCommand> compileCommands;
};
} // namespace ClangBackEnd
#endif // CLANGBACKEND_REFACTORINGCOMPILATIONDATABASE_H

View File

@@ -0,0 +1,65 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "refactoringserver.h"
#include "symbolfinder.h"
#include <refactoringclientinterface.h>
#include <requestsourcelocationforrenamingmessage.h>
#include <sourcelocationsforrenamingmessage.h>
#include <QCoreApplication>
namespace ClangBackEnd {
RefactoringServer::RefactoringServer()
{
}
void RefactoringServer::end()
{
QCoreApplication::exit();
}
void RefactoringServer::requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message)
{
SymbolFinder symbolFinder(message.line(), message.column());
symbolFinder.addFile(message.filePath().directory(),
message.filePath().name(),
message.unsavedContent(),
message.commandLine());
symbolFinder.findSymbol();
client()->sourceLocationsForRenamingMessage(SourceLocationsForRenamingMessage(
symbolFinder.takeSymbolName(),
symbolFinder.takeSourceLocations(),
message.textDocumentRevision()));
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,44 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef CLANGBACKEND_REFACTORINGSERVER_H
#define CLANGBACKEND_REFACTORINGSERVER_H
#include <refactoringserverinterface.h>
namespace ClangBackEnd {
class RefactoringServer : public RefactoringServerInterface
{
public:
RefactoringServer();
void end() override;
void requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) override;
};
} // namespace ClangBackEnd
#endif // CLANGBACKEND_REFACTORINGSERVER_H

View File

@@ -0,0 +1,83 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "sourcefilecallbacks.h"
#include "macropreprocessorcallbacks.h"
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Lex/Preprocessor.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#include <memory>
namespace ClangBackEnd {
SourceFileCallbacks::SourceFileCallbacks(uint line, uint column)
: line(line),
column(column)
{
}
bool SourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerInstance, llvm::StringRef /*fileName*/)
{
auto &preprocessor = compilerInstance.getPreprocessor();
macroPreprocessorCallbacks = new MacroPreprocessorCallbacks(sourceLocationsContainer,
symbolName,
preprocessor,
line,
column);
preprocessor.addPPCallbacks(std::unique_ptr<clang::PPCallbacks>(macroPreprocessorCallbacks));
return true;
}
SourceLocationsContainer SourceFileCallbacks::takeSourceLocations()
{
return std::move(sourceLocationsContainer);
}
Utils::SmallString SourceFileCallbacks::takeSymbolName()
{
return std::move(symbolName);
}
bool SourceFileCallbacks::hasSourceLocations() const
{
return sourceLocationsContainer.hasContent();
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** 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 <sourcelocationscontainer.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/Tooling/Tooling.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
namespace llvm {
class StringRef;
}
namespace clang {
class CompilerInstance;
}
namespace ClangBackEnd {
class MacroPreprocessorCallbacks;
class SourceLocationsContainer;
class SourceFileCallbacks : public clang::tooling::SourceFileCallbacks
{
public:
SourceFileCallbacks(uint line, uint column);
bool handleBeginSource(clang::CompilerInstance &compilerInstance,
llvm::StringRef fileName) override;
SourceLocationsContainer takeSourceLocations();
Utils::SmallString takeSymbolName();
bool hasSourceLocations() const;
private:
SourceLocationsContainer sourceLocationsContainer;
Utils::SmallString symbolName;
MacroPreprocessorCallbacks *macroPreprocessorCallbacks;
uint line;
uint column;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,80 @@
/****************************************************************************
**
** 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 <sourcelocationscontainer.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/Basic/SourceManager.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/FileUtilities.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
namespace ClangBackEnd {
inline
Utils::SmallString absolutePath(const char *path)
{
llvm::SmallString<256> absolutePath(path);
if (!llvm::sys::path::is_absolute(absolutePath))
llvm::sys::fs::make_absolute(absolutePath);
return Utils::SmallString(absolutePath.begin(), absolutePath.end());
}
inline
void appendSourceLocationsToSourceLocationsContainer(
ClangBackEnd::SourceLocationsContainer &sourceLocationsContainer,
const std::vector<clang::SourceLocation> &sourceLocations,
const clang::SourceManager &sourceManager)
{
sourceLocationsContainer.reserve(sourceLocations.size());
for (const auto &sourceLocation : sourceLocations) {
clang::FullSourceLoc fullSourceLocation(sourceLocation, sourceManager);
auto fileId = fullSourceLocation.getFileID();
auto fileEntry = sourceManager.getFileEntryForID(fileId);
auto fileName = fileEntry->getName();
auto fileDirectoryPath = absolutePath(fileEntry->getDir()->getName());
sourceLocationsContainer.insertFilePath(fileId.getHashValue(),
std::move(fileDirectoryPath),
fileName);
sourceLocationsContainer.insertSourceLocation(fileId.getHashValue(),
fullSourceLocation.getSpellingLineNumber(),
fullSourceLocation.getSpellingColumnNumber());
}
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "symbolfinder.h"
#include "refactoringcompilationdatabase.h"
#include "sourcefilecallbacks.h"
#include "symbollocationfinderaction.h"
namespace ClangBackEnd {
SymbolFinder::SymbolFinder(uint line, uint column)
: usrFindingAction(line, column),
sourceFileCallbacks(line, column)
{
}
namespace {
// use std::filesystem::path if it is supported by all compilers
std::string toNativePath(std::string &&path)
{
#ifdef WIN32
std::transform(path.begin(), path.end(), path.begin(), [] (char sign) {
return sign == '/' ? '\\' : sign;
});
#endif
return std::move(path);
}
}
void SymbolFinder::addFile(std::string &&directory,
std::string &&fileName,
std::string &&content,
std::vector<std::string> &&commandLine)
{
fileContents.emplace_back(toNativePath(std::move(directory)),
std::move(fileName),
std::move(content),
std::move(commandLine));
}
void SymbolFinder::findSymbol()
{
RefactoringCompilationDatabase compilationDatabase;
for (auto &&fileContent : fileContents)
compilationDatabase.addFile(fileContent.directory, fileContent.fileName, fileContent.commandLine);
std::vector<std::string> files;
for (auto &&fileContent : fileContents)
files.push_back(fileContent.filePath);
clang::tooling::ClangTool tool(compilationDatabase, files);
for (auto &&fileContent : fileContents) {
if (!fileContent.content.empty())
tool.mapVirtualFile(fileContent.filePath, fileContent.content);
}
tool.run(clang::tooling::newFrontendActionFactory(&usrFindingAction, &sourceFileCallbacks).get());
if (sourceFileCallbacks.hasSourceLocations()) {
sourceLocations_ = sourceFileCallbacks.takeSourceLocations();
symbolName = sourceFileCallbacks.takeSymbolName();
} else {
symbolLocationFinderAction.setUnifiedSymbolResolutions(usrFindingAction.takeUnifiedSymbolResolutions());
tool.run(clang::tooling::newFrontendActionFactory(&symbolLocationFinderAction).get());
sourceLocations_ = symbolLocationFinderAction.takeSourceLocations();
symbolName = usrFindingAction.takeSymbolName();
}
}
Utils::SmallString SymbolFinder::takeSymbolName()
{
return std::move(symbolName);
}
const std::vector<USRName> &SymbolFinder::unifiedSymbolResolutions()
{
return symbolLocationFinderAction.unifiedSymbolResolutions();
}
const SourceLocationsContainer &SymbolFinder::sourceLocations() const
{
return sourceLocations_;
}
SourceLocationsContainer SymbolFinder::takeSourceLocations()
{
return std::move(sourceLocations_);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,97 @@
/****************************************************************************
**
** 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 "findusrforcursoraction.h"
#include "symbollocationfinderaction.h"
#include "sourcefilecallbacks.h"
#include <sourcelocationscontainer.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "clang/Tooling/Refactoring.h"
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#include <string>
#include <vector>
namespace ClangBackEnd {
struct FileContent
{
FileContent(const std::string &directory,
const std::string &fileName,
const std::string &content,
const std::vector<std::string> &commandLine)
: directory(directory),
fileName(fileName),
filePath(directory + nativeSeperator + fileName),
content(content),
commandLine(commandLine)
{}
std::string directory;
std::string fileName;
std::string filePath;
std::string content;
std::vector<std::string> commandLine;
};
class SymbolFinder
{
public:
SymbolFinder(uint line, uint column);
void addFile(std::string &&directory,
std::string &&fileName,
std::string &&content,
std::vector<std::string> &&commandLine);
void findSymbol();
Utils::SmallString takeSymbolName();
const std::vector<USRName> &unifiedSymbolResolutions();
const ClangBackEnd::SourceLocationsContainer &sourceLocations() const;
ClangBackEnd::SourceLocationsContainer takeSourceLocations();
private:
Utils::SmallString symbolName;
USRFindingAction usrFindingAction;
SymbolLocationFinderAction symbolLocationFinderAction;
SourceFileCallbacks sourceFileCallbacks;
std::vector<FileContent> fileContents;
ClangBackEnd::SourceLocationsContainer sourceLocations_;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,90 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "symbollocationfinderaction.h"
#include "sourcelocationsutils.h"
#include "findlocationsofusrs.h"
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h>
#include <memory>
namespace ClangBackEnd {
class FindingSymbolsASTConsumer : public clang::ASTConsumer
{
public:
FindingSymbolsASTConsumer(std::vector<USRName> &unifiedSymbolResolutions)
: unifiedSymbolResolutions(unifiedSymbolResolutions)
{
}
void HandleTranslationUnit(clang::ASTContext &context) override
{
std::vector<clang::SourceLocation> sourceLocations;
auto &&sourceLocationsOfUsr = takeLocationsOfUSRs(unifiedSymbolResolutions, context.getTranslationUnitDecl());
sourceLocations.insert(sourceLocations.end(),
sourceLocationsOfUsr.begin(),
sourceLocationsOfUsr.end());
std::sort(sourceLocations.begin(), sourceLocations.end());
auto newEnd = std::unique(sourceLocations.begin(), sourceLocations.end());
sourceLocations.erase(newEnd, sourceLocations.end());
updateSourceLocations(sourceLocations, context.getSourceManager());
}
void updateSourceLocations(const std::vector<clang::SourceLocation> &sourceLocations,
const clang::SourceManager &sourceManager)
{
appendSourceLocationsToSourceLocationsContainer(*sourceLocationsContainer, sourceLocations, sourceManager);
}
void setSourceLocations(ClangBackEnd::SourceLocationsContainer *sourceLocations)
{
sourceLocationsContainer = sourceLocations;
}
private:
ClangBackEnd::SourceLocationsContainer *sourceLocationsContainer = nullptr;
std::vector<USRName> &unifiedSymbolResolutions;
};
std::unique_ptr<clang::ASTConsumer> SymbolLocationFinderAction::newASTConsumer()
{
auto consumer = std::unique_ptr<FindingSymbolsASTConsumer>(new FindingSymbolsASTConsumer(unifiedSymbolResolutions_));
consumer->setSourceLocations(&sourceLocations);
return std::move(consumer);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** 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 "clangrefactoringbackend_global.h"
#include <sourcelocationscontainer.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <clang/Tooling/Refactoring.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
namespace clang {
class ASTConsumer;
};
namespace ClangBackEnd {
class SymbolLocationFinderAction
{
public:
std::unique_ptr<clang::ASTConsumer> newASTConsumer();
SourceLocationsContainer takeSourceLocations()
{
return std::move(sourceLocations);
}
void setUnifiedSymbolResolutions(std::vector<USRName> &&unifiedSymbolResolutions)
{
unifiedSymbolResolutions_ = std::move(unifiedSymbolResolutions);
}
const std::vector<USRName> &unifiedSymbolResolutions() const
{
return unifiedSymbolResolutions_;
}
private:
ClangBackEnd::SourceLocationsContainer sourceLocations;
std::vector<USRName> unifiedSymbolResolutions_;
};
} // namespace ClangBackEnd