Skip to content

Commit

Permalink
Merge pull request #76 from samanpa/optional_type
Browse files Browse the repository at this point in the history
Improve support for locating declRefs that are used in a macro
  • Loading branch information
samanpa authored May 19, 2023
2 parents 2eb1d0c + 37b8aeb commit b0a6d6d
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 68 deletions.
23 changes: 18 additions & 5 deletions src/collectors/include_graph/include_graph_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,17 @@ void add_redeclaration(clang::CompilerInstance *ci, IncludeGraphData *data,
data->redeclarations);
}

// Gets a sensible clang::SourceLocation even in the presence of a macro.
clang::SourceLocation get_canonical_location(clang::SourceManager &sm,
clang::SourceLocation loc) {
clang::SourceLocation spellingLoc = sm.getSpellingLoc(loc);
// this usually happens when there is token pasting
if (sm.isWrittenInScratchSpace(spellingLoc)) {
loc = sm.getExpansionRange(loc).getBegin();
}
return loc;
}

void add_decl_reference(clang::CompilerInstance *ci, IncludeGraphData *data,
const clang::DeclRefExpr *e) {

Expand All @@ -205,9 +216,10 @@ void add_decl_reference(clang::CompilerInstance *ci, IncludeGraphData *data,
if (!d)
return;
clang::SourceLocation locDef = d->getLocation();
clang::SourceLocation expansionLoc = ci->getSourceManager().getExpansionLoc(locUse);
clang::SourceLocation locUseCanonical =
get_canonical_location(ci->getSourceManager(), locUse);

add_usage(ci, data, expansionLoc, locDef, e, data->decl_references);
add_usage(ci, data, locUseCanonical, locDef, e, data->decl_references);
}

template <typename T>
Expand All @@ -234,7 +246,7 @@ bool check_for_first_end(clang::CompilerInstance *ci, IncludeGraphData *data,
}

void add_type_reference(clang::CompilerInstance *ci, IncludeGraphData *data,
const clang::TypeLoc *n, const clang::Decl* decl) {
const clang::TypeLoc *n, const clang::Decl *decl) {

const clang::Type *t = n->getTypePtr();
if (!decl)
Expand All @@ -258,8 +270,9 @@ void add_type_reference(clang::CompilerInstance *ci, IncludeGraphData *data,
return;
}

add_usage(ci, data, ci->getSourceManager().getExpansionLoc(n->getBeginLoc()),
decl->getLocation(), n, data->type_references);
clang::SourceLocation locUse =
get_canonical_location(ci->getSourceManager(), n->getBeginLoc());
add_usage(ci, data, locUse, decl->getLocation(), n, data->type_references);
}
} // namespace include_graph
} // namespace collectors
Expand Down
82 changes: 47 additions & 35 deletions t/043-variable-access-through-expansion.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@

#include <gtest/gtest.h>

#include <clangmetatool/meta_tool_factory.h>
#include <clangmetatool/meta_tool.h>
#include <clangmetatool/collectors/include_graph.h>
#include <clangmetatool/meta_tool.h>
#include <clangmetatool/meta_tool_factory.h>

#include <clang/Frontend/FrontendAction.h>
#include <clang/Tooling/Core/Replacement.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
#include <clang/Tooling/Core/Replacement.h>
#include <clang/Tooling/Refactoring.h>
#include <clang/Tooling/Tooling.h>
#include <llvm/Support/CommandLine.h>

class MyTool {
private:
clang::CompilerInstance* ci;
clang::CompilerInstance *ci;
clangmetatool::collectors::IncludeGraph graph;

public:
MyTool(clang::CompilerInstance* ci, clang::ast_matchers::MatchFinder *f)
:ci(ci), graph(ci, f) {
}
void postProcessing
(std::map<std::string, clang::tooling::Replacements> &replacementsMap) {
MyTool(clang::CompilerInstance *ci, clang::ast_matchers::MatchFinder *f)
: ci(ci), graph(ci, f) {}
void postProcessing(
std::map<std::string, clang::tooling::Replacements> &replacementsMap) {
clangmetatool::collectors::IncludeGraphData *data = graph.getData();

// file ID 0 to 1, aka foo.cpp to paste.h
Expand All @@ -33,56 +33,68 @@ class MyTool {
// file ID from 0 to 2, aka foo.cpp to global.h
edge = std::make_pair(0, 2);
ASSERT_EQ(data->usage_reference_count.count(edge), 1);
// GLOBAL1 .. GLOBAL4 are referenced
ASSERT_EQ(data->usage_reference_count[edge], 4);
// see comments in foo.cpp about reference counts
ASSERT_EQ(data->usage_reference_count[edge], 6);

// file ID from 2 to 1, aka paste.h to global.h
// file ID from 0 to 3, aka foo.cpp to macro.h
edge = std::make_pair(0, 3);
// ANOTHER_PASTE & REFERENCE_GLOBAL1
ASSERT_EQ(data->usage_reference_count[edge], 2);

// file ID from 0 to 5, aka foo.cpp to indirect.h
edge = std::make_pair(0, 3);
// ANOTHER_PASTE & REFERENCE_GLOBAL1
ASSERT_EQ(data->usage_reference_count[edge], 2);

// file ID from 1 to 2, aka paste.h to global.h
edge = std::make_pair(1, 2);
ASSERT_EQ(data->usage_reference_count.count(edge), 1);
// the macro usages in foo.cpp have the reference counts
ASSERT_EQ(data->usage_reference_count[edge], 0);

// file ID from 0 to 3, aka foo.cpp to macro.h
edge = std::make_pair(0, 3);
ASSERT_EQ(data->usage_reference_count[edge], 2); // USE 2 macros from here

// file ID from 3 to 2, aka macro.h to global.h
edge = std::make_pair(3, 2);
// Even though macro.h has a "spelling" of GLOBAL3 in macro.h it does
// not include global.h and does not directly reference GLOBAL3
// only callers of the macro actually reference global.h
// The call to REFERENCE_GLOBAL3 in foo.cpp has spelling of GLOBAL3
// in macro.h
ASSERT_EQ(data->usage_reference_count.count(edge), 1);
ASSERT_EQ(data->usage_reference_count[edge], 1);

// file ID from 4 to 2, aka indirect.h to global.h
edge = std::make_pair(4, 2);
ASSERT_EQ(data->usage_reference_count.count(edge), 0);
ASSERT_EQ(data->usage_reference_count[edge], 0);
}

// file ID from 4 to 1, aka indirect.h to paste.h
edge = std::make_pair(4, 1);
ASSERT_EQ(data->usage_reference_count.count(edge), 1);
ASSERT_EQ(data->usage_reference_count[edge], 2);
}
};

TEST(use_meta_tool, factory) {
llvm::cl::OptionCategory MyToolCategory("my-tool options");

const char* argv[] = {
"foo",
CMAKE_SOURCE_DIR "/t/data/043-variable-access-through-expansion/foo.cpp",
"--",
"-xc++"
};
const char *argv[] = {"foo",
CMAKE_SOURCE_DIR
"/t/data/043-variable-access-through-expansion/foo.cpp",
"--", "-xc++"};
int argc = sizeof(argv) / sizeof(argv[0]);

auto result = clang::tooling::CommonOptionsParser::create(
argc, argv, MyToolCategory, llvm::cl::OneOrMore);
argc, argv, MyToolCategory, llvm::cl::OneOrMore);
ASSERT_TRUE(!!result);
clang::tooling::CommonOptionsParser& optionsParser = result.get();
clang::tooling::CommonOptionsParser &optionsParser = result.get();

clang::tooling::RefactoringTool tool
( optionsParser.getCompilations(),
optionsParser.getSourcePathList());
clang::tooling::RefactoringTool tool(optionsParser.getCompilations(),
optionsParser.getSourcePathList());

clangmetatool::MetaToolFactory< clangmetatool::MetaTool<MyTool> >
raf(tool.getReplacements());
clangmetatool::MetaToolFactory<clangmetatool::MetaTool<MyTool>> raf(
tool.getReplacements());

int r = tool.runAndSave(&raf);
ASSERT_EQ(0, r);
}


// ----------------------------------------------------------------------------
// Copyright 2023 Bloomberg Finance L.P.
//
Expand Down
55 changes: 29 additions & 26 deletions t/044-type-access-through-expansion.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,73 @@

#include <gtest/gtest.h>

#include <clangmetatool/meta_tool_factory.h>
#include <clangmetatool/meta_tool.h>
#include <clangmetatool/collectors/include_graph.h>
#include <clangmetatool/meta_tool.h>
#include <clangmetatool/meta_tool_factory.h>

#include <clang/Frontend/FrontendAction.h>
#include <clang/Tooling/Core/Replacement.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
#include <clang/Tooling/Core/Replacement.h>
#include <clang/Tooling/Refactoring.h>
#include <clang/Tooling/Tooling.h>
#include <llvm/Support/CommandLine.h>

class MyTool {
private:
clang::CompilerInstance* ci;
clang::CompilerInstance *ci;
clangmetatool::collectors::IncludeGraph graph;

public:
MyTool(clang::CompilerInstance* ci, clang::ast_matchers::MatchFinder *f)
:ci(ci), graph(ci, f) {
}
void postProcessing
(std::map<std::string, clang::tooling::Replacements> &replacementsMap) {
MyTool(clang::CompilerInstance *ci, clang::ast_matchers::MatchFinder *f)
: ci(ci), graph(ci, f) {}
void postProcessing(
std::map<std::string, clang::tooling::Replacements> &replacementsMap) {
clangmetatool::collectors::IncludeGraphData *data = graph.getData();

// file ID 0 to 1, aka foo.cpp to foo.h
auto edge = std::make_pair(0, 1);
ASSERT_EQ(data->usage_reference_count.count(edge), 1);
ASSERT_EQ(data->usage_reference_count[edge], 1);
ASSERT_EQ(data->usage_reference_count[edge], 0);

// file ID from 0 to 2, aka foo.cpp to macro.h
edge = std::make_pair(0, 2);
ASSERT_EQ(data->usage_reference_count.count(edge), 1);
// We reference the macros in macro.h 3 times.
ASSERT_EQ(data->usage_reference_count[edge], 3);
}

// file ID from 1 to 2, aka macro.h to foo.h
edge = std::make_pair(2, 1);
ASSERT_EQ(data->usage_reference_count.count(edge), 1);
// We reference the type in foo.h 3 times, but type declarations are
// only stored once
ASSERT_EQ(data->usage_reference_count[edge], 1);
}
};

TEST(use_meta_tool, factory) {
llvm::cl::OptionCategory MyToolCategory("my-tool options");

const char* argv[] = {
"foo",
CMAKE_SOURCE_DIR "/t/data/044-type-access-through-expansion/foo.cpp",
"--",
"-xc++"
};
const char *argv[] = {"foo",
CMAKE_SOURCE_DIR
"/t/data/044-type-access-through-expansion/foo.cpp",
"--", "-xc++"};
int argc = sizeof(argv) / sizeof(argv[0]);

auto result = clang::tooling::CommonOptionsParser::create(
argc, argv, MyToolCategory, llvm::cl::OneOrMore);
argc, argv, MyToolCategory, llvm::cl::OneOrMore);
ASSERT_TRUE(!!result);
clang::tooling::CommonOptionsParser& optionsParser = result.get();
clang::tooling::CommonOptionsParser &optionsParser = result.get();

clang::tooling::RefactoringTool tool
( optionsParser.getCompilations(),
optionsParser.getSourcePathList());
clang::tooling::RefactoringTool tool(optionsParser.getCompilations(),
optionsParser.getSourcePathList());

clangmetatool::MetaToolFactory< clangmetatool::MetaTool<MyTool> >
raf(tool.getReplacements());
clangmetatool::MetaToolFactory<clangmetatool::MetaTool<MyTool>> raf(
tool.getReplacements());

int r = tool.runAndSave(&raf);
ASSERT_EQ(0, r);
}


// ----------------------------------------------------------------------------
// Copyright 2023 Bloomberg Finance L.P.
//
Expand Down
23 changes: 21 additions & 2 deletions t/data/043-variable-access-through-expansion/foo.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
#include "paste.h"
#include "macro.h"
#include "global.h"
#include "indirect.h"

#define REFERENCE_GLOBAL1() GLOBAL1

int bar()
{
return PASTE(GLO, BAL1) + PASTE(GL, OBAL2);
return PASTE(GLO, BAL1) // 1st use of global.h
+ PASTE(GL, OBAL2) // 2nd use of global.h
+ REFERENCE_GLOBAL1() // 3rd use of global.h (no scratch space)
;
}

int baz()
{
return ANOTHER_PASTE(GL, OBAL4) + REFERENCE_GLOBAL3();
return ANOTHER_PASTE(GL, OBAL4) // 4th use of global.h
+ REFERENCE_GLOBAL3() // not a use of global.h (no scratch space)
;
}

int indirect()
{
return INDIRECT_PASTE(GL, OBAL5); // 5th use of global.h
}


int indirect2()
{
return INDIRECT_REFERENCE_GLOBAL6(); // 6th use of global.h
}
2 changes: 2 additions & 0 deletions t/data/043-variable-access-through-expansion/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ int GLOBAL1;
int GLOBAL2;
int GLOBAL3;
int GLOBAL4;
int GLOBAL5;
int GLOBAL6;

#endif
8 changes: 8 additions & 0 deletions t/data/043-variable-access-through-expansion/indirect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "paste.h"

#define INDIRECT_PASTE(a, b) ( \
PASTE(a, b) \
)

// Does not counts as an access to GLOBAL6
#define INDIRECT_REFERENCE_GLOBAL6() INDIRECT_PASTE(GLOB, AL6)

0 comments on commit b0a6d6d

Please sign in to comment.