Skip to content
This repository has been archived by the owner on Oct 13, 2021. It is now read-only.

Commit

Permalink
Put the macro definition tooltip on macro refs rather than macro defs.
Browse files Browse the repository at this point in the history
…Close #518.
  • Loading branch information
erikrose committed May 27, 2016
2 parents 72a4976 + 25081da commit 9ef9d90
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 14 deletions.
40 changes: 27 additions & 13 deletions dxr/plugins/clang/dxr-index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ class IndexConsumer : public ASTConsumer,
SourceManager &sm;
std::ostream *out;
std::map<std::string, FileInfoPtr> relmap;
// Map the SourceLocation of a macro to the text of the macro def.
std::map<SourceLocation, std::string> macromap;
LangOptions &features;
#if CLANG_AT_LEAST(3, 6)
std::unique_ptr<DiagnosticConsumer> inner;
Expand Down Expand Up @@ -1129,32 +1131,39 @@ class IndexConsumer : public ASTConsumer,
} else {
defnStart = nameLen;
}
// Find the first non-whitespace character for the definition.
for (; defnStart < length; defnStart++) {
switch (contents[defnStart]) {
case ' ': case '\t': case '\v': case '\r': case '\n': case '\f':
continue;
bool hasArgs = (argsEnd - argsStart > 2); // An empty '()' doesn't count.
if (!hasArgs) {
// Skip leading whitespace in the definition up to and including any first
// line continuation.
for (; defnStart < length; defnStart++) {
switch (contents[defnStart]) {
case ' ': case '\t': case '\v': case '\r': case '\n': case '\f':
continue;
case '\\':
if (defnStart + 2 < length && contents[defnStart + 1] == '\n') {
defnStart += 2;
}
break;
}
break;
}
break;
}
beginRecord("macro", nameStart);
recordValue("loc", locationToString(nameStart));
recordValue("locend", locationToString(afterToken(nameStart)));
recordValue("name", std::string(contents, nameLen));
if (argsStart > 0) {
recordValue("args", std::string(contents + argsStart,
argsEnd - argsStart), true);
}
if (defnStart < length) {
std::string text = std::string(contents + defnStart,
length - defnStart);
std::string text;
if (hasArgs) // Give the argument list.
text = std::string(contents + argsStart, argsEnd - argsStart);
text += std::string(contents + defnStart, length - defnStart);
// FIXME: handle non-ASCII characters better
for (size_t i = 0; i < text.size(); ++i) {
if ((text[i] < ' ' || text[i] >= 0x7F) &&
text[i] != '\t' && text[i] != '\n')
text[i] = '?';
}
recordValue("text", text, true);
macromap.insert(make_pair(nameStart, text));
}
*out << std::endl;
}
Expand All @@ -1177,6 +1186,11 @@ class IndexConsumer : public ASTConsumer,
recordValue("loc", locationToString(refLoc));
recordValue("locend", locationToString(afterToken(refLoc)));
recordValue("kind", "macro");
std::map<SourceLocation, std::string>::const_iterator it =
macromap.find(macroLoc);
if (it != macromap.end()) {
recordValue("text", it->second, true);
}
*out << std::endl;
}

Expand Down
40 changes: 39 additions & 1 deletion dxr/plugins/clang/tests/test_macros.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from dxr.plugins.clang.tests import CSingleFileTestCase, MINIMAL_MAIN

from nose.tools import ok_

class MacroTests(CSingleFileTestCase):
"""Tests for ``macro`` queries"""
Expand Down Expand Up @@ -30,7 +31,7 @@ class MacroRefTests(CSingleFileTestCase):
#ifndef MACRO
#endif
#if defined(MACRO)
#endif
Expand Down Expand Up @@ -136,3 +137,40 @@ def test_decls(self):
self.found_line_eq('+var:foo()::b', 'DECLARE(<b>b</b>);')
self.found_line_eq('+var:foo()::c', 'DECLARE2(<b>c</b>, d);')
self.found_line_eq('+var:foo()::d', 'DECLARE2(c, <b>d</b>);')


class MacroRefTitleTests(CSingleFileTestCase):

source = r"""
#define SD \
int s;\
int d
SD;
#define ADD(x, y) ((x) + (y))
int c = ADD(0, 0);
""" + MINIMAL_MAIN

def test_macro_titles(self):
"""Test that a ref to a macro gets a title tooltip containing the
definition of the macro, and that the macro def doesn't get a title.
Also make sure the macro tooltip for a macro without args skips the
macro's leading whitespace up to and including an initial backslash
newline.
"""
markup = self.source_page('main.cpp')
# Check that the SD ref gets a title. Also since SD has no arguments,
# we skip whitespace up to and including the initial backslash newline.
ok_('title=" int s;\\\n int d">SD</a>;' in markup, msg=markup)
# The SD def doesn't get a title.
ok_('title=" int s;\\\n int d;">SD</a> \\' not in markup)

def test_macro_title_args(self):
"""Test that a macro with args gets the args included in the tooltip."""
markup = self.source_page('main.cpp')
# We include everything starting from the opening '(' of the arguments.
ok_('title="(x, y) ((x) + (y))">ADD</a>(0, 0);' in markup, msg=markup)

0 comments on commit 9ef9d90

Please sign in to comment.